org.cryptocall.ui.WizardActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.cryptocall.ui.WizardActivity.java

Source

/*
 * Copyright (C) 2011-2013 Sergej Dechand <cryptocall@serj.de>
 *                         Dominik Schrmann <dominik@dominikschuermann.de>
 * 
 * This file is part of CryptoCall.
 * 
 * CryptoCall 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.
 *
 * CryptoCall 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 CryptoCall.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package org.cryptocall.ui;

import org.cryptocall.R;
import org.cryptocall.util.Constants;
import org.cryptocall.util.Log;
import org.cryptocall.util.PreferencesHelper;
import org.cryptocall.util.ProtectedEmailUtils;
import org.sufficientlysecure.keychain.integration.KeychainData;
import org.sufficientlysecure.keychain.integration.KeychainIntentHelper;
import org.sufficientlysecure.keychain.integration.KeychainUtil;

import com.actionbarsherlock.app.SherlockFragmentActivity;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;

public class WizardActivity extends SherlockFragmentActivity {
    private KeychainIntentHelper mKeychainIntentHelper;

    private int mCurrentScreen;

    // values for mCurrentScreen
    private static final int SCREEN_MAIN = 0;
    private static final int SCREEN_GENERATE_KEYRING_INPUT = 1;
    private static final int SCREEN_SELECT_KEYRING = 2;
    private static final int SCREEN_SUCCESS = 3;

    Button mBackButton;
    Button mNextButton;
    MainFragment mMainFragment;
    GenerateKeyringFragment mGenerateKeyRingFragment;
    SelectKeyringFragment mSelectKeyringFragment;
    SuccessFragment mSuccessFragment;

    KeychainData mKeychainData;

    private static long mMasterKeyId;
    private static String mProtectedEmail;
    private static String mTelephoneNumber;

    public static void prefillTelephoneNumber(Context context, EditText editText) {
        // prefill telephone number if available
        TelephonyManager tMgr = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        String telephoneNumber = tMgr.getLine1Number();
        if (telephoneNumber != null) {
            Log.d(Constants.TAG, "TelephoneNumber: " + telephoneNumber);
            editText.setText(telephoneNumber);
        } else {
            Log.d(Constants.TAG, "TelephoneNumber could not be retrived with TelephonyManager!");
        }
    }

    /**
     * Checks if text of given EditText is not empty. If it is empty an error is set and the
     * EditText gets the focus.
     * 
     * @param context
     * @param editText
     * @return true if EditText is not empty
     */
    private static boolean isEditTextNotEmpty(Context context, EditText editText) {
        boolean output = true;
        if (editText.getText().toString().length() == 0) {
            editText.setError(context.getString(R.string.wizard_error_blank));
            editText.requestFocus();
            output = false;
        } else {
            editText.setError(null);
        }

        return output;
    }

    /**
     * Checks if text of given EditText contains a valid international telephone number. If not an
     * error is set and the EditText gets the focus.
     * 
     * @param context
     * @param editText
     * @return true if valid telephone number
     */
    private static boolean isEditTextValidTelephoneNumber(Context context, EditText editText) {
        boolean output = true;

        if (!PhoneNumberUtils.isWellFormedSmsAddress(editText.getText().toString())) {
            editText.setError(context.getString(R.string.wizard_error_blank));
            editText.requestFocus();
            output = false;
        } else {
            if (!editText.getText().toString().startsWith("+")
                    || !PhoneNumberUtils.isGlobalPhoneNumber(editText.getText().toString())) {
                editText.setError(context.getString(R.string.wizard_error_not_international));
                editText.requestFocus();
                output = false;
            } else {
                editText.setError(null);
            }
        }

        return output;
    }

    public static class MainFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            return inflater.inflate(R.layout.wizard_main_fragment, container, false);
        }
    }

    public static class GenerateKeyringFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.wizard_generate_keyring_fragment, container, false);

            // prefill telephone number if available
            EditText telephoneNumberEdit = (EditText) view
                    .findViewById(R.id.wizard_generate_keyring_telephone_number);
            WizardActivity.prefillTelephoneNumber(getActivity(), telephoneNumberEdit);
            return view;
        }
    }

    public static class SelectKeyringFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.wizard_select_keyring_fragment, container, false);

            // prefill telephone number if available
            EditText telephoneNumberEdit = (EditText) view
                    .findViewById(R.id.wizard_select_keyring_telephone_number);
            WizardActivity.prefillTelephoneNumber(getActivity(), telephoneNumberEdit);
            return view;
        }
    }

    public static class SuccessFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.wizard_success_fragment, container, false);

            TextView telephoneNumberTextView = (TextView) view.findViewById(R.id.wizard_success_telephone_number);
            TextView protectedEmailTextView = (TextView) view.findViewById(R.id.wizard_success_protected_email);

            telephoneNumberTextView.setText(mTelephoneNumber);
            protectedEmailTextView.setText(mProtectedEmail);

            return view;
        }
    }

    /**
     * Loads new fragment
     * 
     * @param fragment
     */
    private void loadFragment(Fragment fragment) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.wizard_fragment_container, fragment);
        fragmentTransaction.commit();
    }

    /**
     * Instantiate View and initialize fragments for this Activity
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mKeychainData = new KeychainData();

        setContentView(R.layout.wizard_activity);
        mBackButton = (Button) findViewById(R.id.wizard_activity_back);
        mNextButton = (Button) findViewById(R.id.wizard_activity_next);

        mMainFragment = new MainFragment();
        loadFragment(mMainFragment);
        mCurrentScreen = SCREEN_MAIN;

        mKeychainIntentHelper = new KeychainIntentHelper(this);
    }

    public void nextOnClick(View view) {
        switch (mCurrentScreen) {
        case SCREEN_MAIN:
            RadioButton generateKeyringRadio = (RadioButton) findViewById(
                    R.id.wizard_activity_generate_keyring_radio);
            RadioButton selectKeyringRadio = (RadioButton) findViewById(R.id.wizard_activity_select_keyring_radio);

            if (generateKeyringRadio.isChecked()) {
                mGenerateKeyRingFragment = new GenerateKeyringFragment();
                loadFragment(mGenerateKeyRingFragment);
                mCurrentScreen = SCREEN_GENERATE_KEYRING_INPUT;
            } else if (selectKeyringRadio.isChecked()) {
                mSelectKeyringFragment = new SelectKeyringFragment();
                loadFragment(mSelectKeyringFragment);
                mCurrentScreen = SCREEN_SELECT_KEYRING;
            }

            break;

        case SCREEN_GENERATE_KEYRING_INPUT:
            EditText generateNicknameEdit = (EditText) findViewById(R.id.wizard_generate_keyring_nickname);
            EditText generateTelephoneNumberEdit = (EditText) findViewById(
                    R.id.wizard_generate_keyring_telephone_number);

            if (isEditTextNotEmpty(this, generateNicknameEdit)
                    && isEditTextValidTelephoneNumber(this, generateTelephoneNumberEdit)) {
                String nickname = generateNicknameEdit.getText().toString();
                String number = generateTelephoneNumberEdit.getText().toString();
                Log.d(Constants.TAG, "nickname: " + nickname);
                Log.d(Constants.TAG, "number: " + number);

                String protectedEmail = ProtectedEmailUtils.generateProtectedEmail(number);
                Log.d(Constants.TAG, "protectedEmail: " + protectedEmail);

                String id = nickname + " (CryptoCall) <" + protectedEmail + ">";

                Log.d(Constants.TAG, "id: " + id);

                mKeychainIntentHelper.createNewKey(id, true, true);
            }
            break;

        case SCREEN_SELECT_KEYRING:
            EditText selectTelephoneNumberEdit = (EditText) findViewById(
                    R.id.wizard_select_keyring_telephone_number);

            if (isEditTextValidTelephoneNumber(this, selectTelephoneNumberEdit)) {
                mKeychainIntentHelper.selectSecretKey();
            }
            break;

        case SCREEN_SUCCESS:
            // save into prefs
            PreferencesHelper.setPgpEmail(this, mProtectedEmail);
            PreferencesHelper.setPgpMasterKeyId(this, mMasterKeyId);
            PreferencesHelper.setTelephoneNumber(this, mTelephoneNumber);

            PreferencesHelper.setFirstStart(this, false);

            // go to base activity
            Intent baseIntent = new Intent(this, BaseActivity.class);
            startActivity(baseIntent);
            finish();

            break;

        default:
            break;
        }

        // set button to "back"
        mBackButton.setText(R.string.button_back);
    }

    public void backOnClick(View view) {
        if (mCurrentScreen == SCREEN_MAIN) {
            finish();
        } else {
            loadFragment(mMainFragment);
            mCurrentScreen = SCREEN_MAIN;
            mBackButton.setText(R.string.button_cancel);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // this updates the mKeychainData object to the result of the methods
        boolean result = mKeychainIntentHelper.onActivityResult(requestCode, resultCode, data, mKeychainData);
        if (result) {
            switch (mCurrentScreen) {
            case SCREEN_GENERATE_KEYRING_INPUT:
                if (resultCode == Activity.RESULT_OK) {
                    Log.d(Constants.TAG, mKeychainData.toString());
                    long generatedKeyId = mKeychainData.getSecretKeyId();
                    String generatedUserId = mKeychainData.getSecretKeyUserId();

                    // TODO: handle keys with many user ids

                    String[] split = KeychainUtil.splitUserId(generatedUserId);
                    String generatedEmail = split[1];
                    Log.d(Constants.TAG, "generatedEmail: " + generatedEmail);
                    byte[] generatedSalt;
                    try {
                        generatedSalt = ProtectedEmailUtils.getSaltFromProtectedEmail(generatedEmail);

                        EditText inputNumberEdit = (EditText) findViewById(
                                R.id.wizard_generate_keyring_telephone_number);

                        String inputNumber = inputNumberEdit.getText().toString();
                        Log.d(Constants.TAG, "inputNumber: " + inputNumber);
                        String protectedInputEmail = ProtectedEmailUtils.generateProtectedEmail(inputNumber,
                                generatedSalt);
                        Log.d(Constants.TAG, "protectedInputEmail: " + protectedInputEmail);

                        if (generatedEmail.equals(protectedInputEmail)) {
                            mMasterKeyId = generatedKeyId;
                            mProtectedEmail = generatedEmail;
                            mTelephoneNumber = inputNumber;

                            mCurrentScreen = SCREEN_SUCCESS;
                            // success fragment is handled in onResume, due to android bug
                            // http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult
                        } else {
                            Toast.makeText(this, R.string.wizard_error_not_matching, Toast.LENGTH_LONG).show();
                        }
                    } catch (Exception e) {
                        Log.e(Constants.TAG, "Parsing problem!", e);
                    }

                }
                break;
            case SCREEN_SELECT_KEYRING:
                if (resultCode == Activity.RESULT_OK) {
                    Log.d(Constants.TAG, mKeychainData.toString());
                    long selectedKeyId = mKeychainData.getSecretKeyId();
                    String selectedUserId = mKeychainData.getSecretKeyUserId();

                    // TODO: handle keys with many user ids

                    String[] split = KeychainUtil.splitUserId(selectedUserId);
                    String selectedEmail = split[1];
                    Log.d(Constants.TAG, "selectedEmail: " + selectedEmail);
                    byte[] selectedSalt;
                    try {
                        selectedSalt = ProtectedEmailUtils.getSaltFromProtectedEmail(selectedEmail);

                        EditText inputNumberEdit = (EditText) findViewById(
                                R.id.wizard_select_keyring_telephone_number);

                        String inputNumber = inputNumberEdit.getText().toString();
                        Log.d(Constants.TAG, "inputNumber: " + inputNumber);
                        String protectedInputEmail = ProtectedEmailUtils.generateProtectedEmail(inputNumber,
                                selectedSalt);
                        Log.d(Constants.TAG, "protectedInputEmail: " + protectedInputEmail);

                        if (selectedEmail.equals(protectedInputEmail)) {
                            mMasterKeyId = selectedKeyId;
                            mProtectedEmail = selectedEmail;
                            mTelephoneNumber = inputNumber;

                            mCurrentScreen = SCREEN_SUCCESS;
                            // success fragment is handled in onResume, due to android bug
                            // http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult
                        } else {
                            Toast.makeText(this, R.string.wizard_error_not_matching, Toast.LENGTH_LONG).show();
                        }
                    } catch (Exception e) {
                        Log.e(Constants.TAG, "Parsing problem!", e);
                    }

                }
                break;

            default:
                break;
            }
        }

        // continue with other activity results
        super.onActivityResult(requestCode, resultCode, data);
    }

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

        if (mCurrentScreen == SCREEN_SUCCESS) {
            mSuccessFragment = new SuccessFragment();
            loadFragment(mSuccessFragment);
            mBackButton.setEnabled(false);
            // set button to "finish"
            mNextButton.setText(R.string.button_finish);
        }
    }

}