com.z299studio.pb.HomeActivity.java Source code

Java tutorial

Introduction

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

Source

/*
* Copyright 2014 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.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;

import java.lang.reflect.Array;

public class HomeActivity extends AppCompatActivity implements AnimatorListener, SyncService.SyncListener,
        FingerprintDialog.FingerprintListener, DecryptTask.OnTaskFinishListener {
    protected Application mApp;
    protected EditText mPwdEdit;
    protected TextView mSyncText;
    protected View mButtonContainer;
    private ProgressBar mProgress;
    private static int mStage;
    private static final int SELECT_SYNC = 0;
    private static final int LOADING = 1;
    private static final int SET_PWD = 2;
    private static final int AUTH = 3;
    private FingerprintManager mFingerprintManager;
    private static final int PERMISSION_REQ_CODE_FP = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mApp = Application.getInstance(this);
        this.setTheme(C.THEMES[Application.Options.mTheme]);
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_home);
        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();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            View v = findViewById(R.id.activity_root);
            v.setBackgroundColor(C.ThemedColors[C.colorPrimary]);
        }
        if (savedInstanceState == null) {
            if (!mApp.hasDataFile()) {
                mStage = SELECT_SYNC;
            } else {
                mStage = AUTH;
            }
            getSupportFragmentManager().beginTransaction().add(R.id.container, HomeFragment.create()).commit();
        } else {
            mStage = savedInstanceState.getInt("home_stage");
        }
        if (!Application.Options.mTour) {
            Intent intent = new Intent(this, TourActivity.class);
            intent.putExtra(C.ACTIVITY, C.Activity.HOME);
            this.startActivity(intent);
            this.finish();
            overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mFingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
            if (mStage == AUTH && mApp.queryFpStatus() == C.Fingerprint.ENABLED) {
                tryUseFingerprint();
            }
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (mStage == LOADING) {
            startSync(false);
        } else {
            mPwdEdit = (EditText) findViewById(R.id.password);
        }
    }

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

    @Override
    protected void onResume() {
        super.onResume();
        popInput();
    }

    @Override
    protected void onPause() {
        if (mPwdEdit != null) {
            mPwdEdit.clearFocus();
            InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(mPwdEdit.getWindowToken(), 0);
        }
        super.onPause();
    }

    public void onConfirm(View view) {
        String password = mPwdEdit.getText().toString();
        if (password.length() < 1) {
            Application.showToast(this, R.string.pwd_wrong, Toast.LENGTH_SHORT);
            return;
        }
        if (mStage == SET_PWD) {
            EditText et_confirm = (EditText) findViewById(R.id.confirm);
            if (password.equals(et_confirm.getText().toString())) {
                et_confirm.clearFocus();
                ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE))
                        .hideSoftInputFromWindow(et_confirm.getWindowToken(), 0);
                mApp.setPassword(password, true);
                new InitTask().execute();
            } else {
                et_confirm.setText("");
                mPwdEdit.setText("");
                Application.showToast(this, R.string.pwd_unmatch, Toast.LENGTH_SHORT);
            }
        } else {
            mApp.setPassword(password, false);
            new DecryptTask(mApp.getData(), mApp.getAppHeaderData(), this).execute(password);
        }
    }

    @Override
    @TargetApi(Build.VERSION_CODES.M)
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResult) {
        if (requestCode == PERMISSION_REQ_CODE_FP && grantResult[0] == PackageManager.PERMISSION_GRANTED) {
            FingerprintDialog.build(Application.Options.mFpStatus == C.Fingerprint.UNKNOWN)
                    .show(getSupportFragmentManager(), "dialog_fp");
        }
    }

    @TargetApi(Build.VERSION_CODES.M)
    private boolean tryUseFingerprint() {
        boolean isHandled = false;
        if (Application.Options.mFpStatus != C.Fingerprint.DISABLED) {
            if (checkSelfPermission(Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[] { Manifest.permission.USE_FINGERPRINT }, PERMISSION_REQ_CODE_FP);
                isHandled = true;
            } else if (mFingerprintManager.isHardwareDetected() && mFingerprintManager.hasEnrolledFingerprints()) {
                if (mPwdEdit != null) {
                    ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE))
                            .hideSoftInputFromWindow(mPwdEdit.getWindowToken(), 0);
                }
                FingerprintDialog.build(Application.Options.mFpStatus == C.Fingerprint.UNKNOWN)
                        .show(getSupportFragmentManager(), "dialog_fp");
                isHandled = true;
            }
        }
        return isHandled;
    }

    public void onSyncSelected(View view) {
        int id = view.getId();
        switch (id) {
        case R.id.btn_gdrive:
        case R.id.btn_gpg:
            mStage = LOADING;
            Application.Options.mSync = id == R.id.btn_gdrive ? C.Sync.GDRIVE : C.Sync.GPGS;
            startSync(true);
            break;
        case R.id.btn_local:
            Application.Options.mSync = C.Sync.NONE;
            mApp.mSP.edit().putInt(C.Sync.SERVER, Application.Options.mSync).apply();
            mStage = SET_PWD;
            startHome();
            break;
        }
    }

    private void startSync(boolean animationOn) {
        Resources r = getResources();
        int strRes[] = { R.string.sync_none, R.string.sync_gpg, R.string.sync_gdrive };
        mButtonContainer = findViewById(R.id.btn_container);
        if (animationOn) {
            mButtonContainer.animate().scaleY(0.0f).setListener(this);
        } else {
            mButtonContainer.setVisibility(View.INVISIBLE);
        }
        mSyncText = (TextView) findViewById(R.id.sync_hint);
        mSyncText.setText(r.getString(R.string.contacting, r.getString(strRes[Application.Options.mSync])));
        ProgressBar pb = (ProgressBar) findViewById(R.id.pb);
        if (animationOn) {
            pb.animate().alpha(1.0f).setStartDelay(300);
            mSyncText.animate().alpha(1.0f).setStartDelay(300);
        } else {
            pb.setAlpha(1.0f);
            mSyncText.setAlpha(1.0f);
        }
        SyncService ss = SyncService.getInstance(this, Application.Options.mSync);
        ss.initialize().setListener(this).connect(0);
    }

    private void startHome() {
        getSupportFragmentManager().beginTransaction()
                .setCustomAnimations(R.anim.expand_from_right, R.anim.collapse_to_left)
                .replace(R.id.container, HomeFragment.create(), null).commit();
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mPwdEdit = (EditText) findViewById(R.id.password);
                popInput();
            }

        }, 300);
    }

    public void startMain() {
        System.gc();
        Application.reset();
        Intent intent = new Intent(HomeActivity.this, MainActivity.class);
        mApp.ignoreNextPause();
        mApp.getAccountManager().setDefaultCategory(-1, getString(R.string.def_category));
        startActivity(intent);
        this.finish();
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        SyncService.getInstance().onActivityResult(requestCode, resultCode, data);
    }

    private void popInput() {
        if (mPwdEdit != null) {
            mPwdEdit.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mPwdEdit.requestFocus();
                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.showSoftInput(mPwdEdit, InputMethodManager.SHOW_FORCED);
                }
            }, 100);

            OnEditorActionListener eal = new OnEditorActionListener() {
                @Override
                public boolean onEditorAction(TextView edit, int id, KeyEvent event) {
                    if (id == EditorInfo.IME_ACTION_DONE) {
                        onConfirm(null);
                        return true;
                    }
                    return false;
                }
            };
            EditText et_confirm = (EditText) findViewById(R.id.confirm);
            if (et_confirm.getVisibility() == View.VISIBLE) {
                mPwdEdit.setImeOptions(EditorInfo.IME_ACTION_NEXT);
                et_confirm.setOnEditorActionListener(eal);
            } else {
                mPwdEdit.setOnEditorActionListener(eal);
            }
        }
    }

    @Override
    public void preExecute() {
        Button okButton = (Button) HomeActivity.this.findViewById(R.id.unlock);
        mProgress = (ProgressBar) HomeActivity.this.findViewById(R.id.pb);
        okButton.setEnabled(false);
        mProgress.setVisibility(View.VISIBLE);
        mApp.onStart();
    }

    @Override
    public void onFinished(boolean isSuccessful, AccountManager manager, String password, byte[] data,
            Application.FileHeader header, Crypto crypto) {
        if (isSuccessful) {
            mApp.setAccountManager(manager, -1, getString(R.string.def_category));
            mApp.setCrypto(crypto);
        }
        if (!isSuccessful) {
            mProgress.setVisibility(View.INVISIBLE);
            mPwdEdit.setText("");
            Application.showToast(HomeActivity.this, R.string.pwd_wrong, Toast.LENGTH_SHORT);
        } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
                || Application.Options.mFpStatus == C.Fingerprint.ENABLED || !tryUseFingerprint()) {
            startMain();
        }
    }

    public static class HomeFragment extends Fragment {

        public static HomeFragment create() {
            return new HomeFragment();
        }

        public HomeFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            int layout;
            if (mStage == LOADING || mStage == SELECT_SYNC) {
                layout = R.layout.fragment_startup;
            } else {
                layout = R.layout.fragment_home;
            }

            View rootView = inflater.inflate(layout, container, false);

            if (layout == R.layout.fragment_home) {
                final Button unlock = (Button) rootView.findViewById(R.id.unlock);
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                    unlock.getBackground().setColorFilter(C.ThemedColors[C.colorAccent], PorterDuff.Mode.SRC_ATOP);
                }
                TextWatcher tw = new TextWatcher() {
                    @Override
                    public void afterTextChanged(Editable s) {
                        if (s.toString().length() < 1) {
                            unlock.setEnabled(false);
                        } else {
                            unlock.setEnabled(true);
                        }
                    }

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

                    @Override
                    public void onTextChanged(CharSequence s, int start, int before, int count) {
                    }
                };
                EditText password = (EditText) rootView.findViewById(R.id.password);
                password.addTextChangedListener(tw);
                if (mStage == AUTH) {
                    EditText confirm = (EditText) rootView.findViewById(R.id.confirm);
                    confirm.setVisibility(View.GONE);
                } else if (mStage == SET_PWD) {
                    TextView tv = (TextView) rootView.findViewById(R.id.title);
                    tv.setText(R.string.set_pwd);
                    unlock.setText(R.string.get_started);
                }
            } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                int ids[] = { R.id.btn_local, R.id.btn_gdrive, R.id.btn_gpg };
                for (int id : ids) {
                    View button = rootView.findViewById(id);
                    button.getBackground().setColorFilter(C.ThemedColors[C.colorAccent], PorterDuff.Mode.SRC_ATOP);
                }
            }
            return rootView;
        }
    }

    @Override
    public void onAnimationStart(Animator animation) {
    }

    @Override
    public void onAnimationEnd(Animator animation) {
        mButtonContainer.setVisibility(View.INVISIBLE);
    }

    @Override
    public void onAnimationCancel(Animator animation) {
    }

    @Override
    public void onAnimationRepeat(Animator animation) {
    }

    @Override
    public void onSyncFailed(int errorCode) {
        mStage = SET_PWD;
        if (errorCode == SyncService.CA.AUTH) {
            Application.Options.mSync = C.Sync.NONE;
            mApp.mSP.edit().putInt(C.Sync.SERVER, C.Sync.NONE).apply();
        }
        startHome();
    }

    @Override
    public void onSyncProgress(int actionCode) {
        if (actionCode == SyncService.CA.AUTH) {
            Resources r = getResources();
            mSyncText.setText(r.getString(R.string.loading,
                    Application.Options.mSync == C.Sync.GDRIVE ? r.getString(R.string.sync_gdrive)
                            : r.getString(R.string.sync_gpg)));
            mApp.mSP.edit().putInt(C.Sync.SERVER, Application.Options.mSync).apply();
        } else if (actionCode == SyncService.CA.DATA_RECEIVED) {
            byte[] data = SyncService.getInstance().requestData();
            Application.getInstance().onSyncSucceed();
            Application.FileHeader fh = Application.FileHeader.parse(data);
            if (fh.valid) {
                mApp.onVersionUpdated(fh.revision);
                mApp.saveData(data, fh);
                mStage = AUTH;
            } else {
                mStage = SET_PWD;
            }
            startHome();
        }
    }

    @Override
    public void onCanceled(boolean isFirstTime) {
        if (isFirstTime) {
            startMain();
        } else {
            popInput();
        }
    }

    @Override
    public void onConfirmed(boolean isFirstTime, byte[] password) {
        if (isFirstTime) {
            startMain();
        } else {
            String pwd = new String(password);
            mApp.setPassword(pwd, false);
            new DecryptTask(mApp.getData(), mApp.getAppHeaderData(), this).execute(pwd);
        }
    }

    private class InitTask extends AsyncTask<String, Void, String> {

        @Override
        protected void onPreExecute() {
            Button okButton = (Button) HomeActivity.this.findViewById(R.id.unlock);
            ProgressBar pb = (ProgressBar) HomeActivity.this.findViewById(R.id.pb);
            okButton.setEnabled(false);
            pb.setVisibility(View.VISIBLE);
        }

        @Override
        protected String doInBackground(String... params) {
            mApp.onStart();
            Resources r = getResources();
            String[] defCategories = r.getStringArray(R.array.category_names);
            int i = 0;
            AccountManager am = new AccountManager(null);
            mApp.setAccountManager(am, -1, getString(R.string.def_category));
            for (String s : defCategories) {
                am.addCategory(i++, s);
            }
            String[] defAccountNames = r.getStringArray(R.array.def_account_names);
            String[] defNames = r.getStringArray(R.array.def_field_names);
            String[] defValues = r.getStringArray(R.array.def_values);
            int[] defTypes = r.getIntArray(R.array.def_field_types);
            TypedArray defAccountData = r.obtainTypedArray(R.array.def_account_data);
            int[] dataDetails;
            AccountManager.Account a;
            for (i = 0; i < defAccountNames.length; ++i) {
                dataDetails = r.getIntArray(defAccountData.getResourceId(i, 0));
                a = am.newAccount(dataDetails[0]);
                a.mProfile = defAccountNames[i];
                for (int j = 1; j < dataDetails.length; j += 3) {
                    try {
                        a.addEntry(defTypes[dataDetails[j + 2]], defNames[dataDetails[j]],
                                defValues[dataDetails[j + 1]]);
                    } catch (ArrayIndexOutOfBoundsException e) {
                        Log.e("Passbook", "This should really not happen.");
                    }
                }
                am.addAccount(dataDetails[0], a);
            }
            defAccountData.recycle();
            return "OK";
        }

        @Override
        protected void onPostExecute(String result) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
                    || Application.Options.mFpStatus == C.Fingerprint.ENABLED || !tryUseFingerprint()) {
                startMain();
            }
        }
    }
}