aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain')
-rw-r--r--OpenKeychain/src/main/AndroidManifest.xml2
-rw-r--r--OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragment.java55
-rw-r--r--OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragmentOld.java926
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java47
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java602
-rw-r--r--OpenKeychain/src/main/res/drawable/nfc.pngbin0 -> 14331 bytes
-rw-r--r--OpenKeychain/src/main/res/layout/alp_42447968_lock_pattern_fragment.xml15
-rw-r--r--OpenKeychain/src/main/res/layout/passphrase_wizard.xml11
-rw-r--r--OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_nfc.xml29
-rw-r--r--OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_passphrase.xml109
-rw-r--r--OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_select_methods.xml89
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml27
13 files changed, 1891 insertions, 22 deletions
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index 193d3863f..9fc79e6f1 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -665,6 +665,8 @@
android:configChanges="orientation|screenSize|keyboard|keyboardHidden"
android:screenOrientation="user"
android:theme="@style/Alp.42447968.Theme.Dialog.Light" />
+ <activity
+ android:name=".ui.PassphraseWizardActivity" />
<!--
NOTE: singleTop is set to get NFC foreground dispatch to work.
Then, all NFC intents will be broadcasted to onNewIntent() of this activity!
diff --git a/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragment.java b/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragment.java
new file mode 100644
index 000000000..318a7c2e5
--- /dev/null
+++ b/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragment.java
@@ -0,0 +1,55 @@
+
+
+package com.haibison.android.lockpattern;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.haibison.android.lockpattern.widget.LockPatternUtils;
+import com.haibison.android.lockpattern.widget.LockPatternView;
+
+
+public class LockPatternFragment extends Fragment {
+ public static final String NUMBER_OF_MEASUREMENTS = "number_of_measurements";
+ public static final String PATTERN_STRING = "pattern_string";
+
+ private String mPatternString;
+ private LockPatternView.OnPatternListener mEvents;
+
+ public static LockPatternFragment newInstance(String pattern) {
+ LockPatternFragment fragment = new LockPatternFragment();
+ Bundle args = new Bundle();
+ args.putString(PATTERN_STRING, pattern);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ public LockPatternFragment() {
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+
+ mEvents = (LockPatternView.OnPatternListener) activity;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ // Get the number of measurements from the bundle, or load the default:
+ mPatternString = getArguments().getString(PATTERN_STRING);
+
+ View rootView = inflater.inflate(R.layout.alp_42447968_lock_pattern_activity, container, false);
+
+ final LockPatternView lpv = (LockPatternView) rootView.findViewById(R.id.alp_42447968_view_lock_pattern);
+ lpv.setPattern(LockPatternView.DisplayMode.Correct, LockPatternUtils.stringToPattern(mPatternString));
+
+ lpv.setOnPatternListener(mEvents);
+
+ return rootView;
+ }
+}
diff --git a/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragmentOld.java b/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragmentOld.java
new file mode 100644
index 000000000..439cf3562
--- /dev/null
+++ b/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragmentOld.java
@@ -0,0 +1,926 @@
+/*
+ * Copyright 2012 Hai Bison
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use getActivity() 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.haibison.android.lockpattern;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.haibison.android.lockpattern.util.IEncrypter;
+import com.haibison.android.lockpattern.util.InvalidEncrypterException;
+import com.haibison.android.lockpattern.util.LoadingDialog;
+import com.haibison.android.lockpattern.util.Settings;
+import com.haibison.android.lockpattern.util.UI;
+import com.haibison.android.lockpattern.widget.LockPatternUtils;
+import com.haibison.android.lockpattern.widget.LockPatternView;
+import com.haibison.android.lockpattern.widget.LockPatternView.Cell;
+import com.haibison.android.lockpattern.widget.LockPatternView.DisplayMode;
+
+import org.sufficientlysecure.keychain.ui.PassphraseWizardActivity;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_CAPTCHA_WIRED_DOTS;
+import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_MAX_RETRIES;
+import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_MIN_WIRED_DOTS;
+import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_STEALTH_MODE;
+import static com.haibison.android.lockpattern.util.Settings.Security.METADATA_AUTO_SAVE_PATTERN;
+import static com.haibison.android.lockpattern.util.Settings.Security.METADATA_ENCRYPTER_CLASS;
+
+/**
+ * Main activity for getActivity() library.
+ * <p>
+ * You can deliver result to {@link android.app.PendingIntent}'s and/ or
+ * {@link android.os.ResultReceiver} too. See {@link #EXTRA_PENDING_INTENT_OK},
+ * {@link #EXTRA_PENDING_INTENT_CANCELLED} and {@link #EXTRA_RESULT_RECEIVER}
+ * for more details.
+ * </p>
+ *
+ * <h1>NOTES</h1>
+ * <ul>
+ * <li>
+ * You must use one of built-in actions when calling getActivity() activity. They start
+ * with {@code ACTION_*}. Otherwise the library might behave strangely (we don't
+ * cover those cases).</li>
+ * <li>You must use one of the themes that getActivity() library supports. They start
+ * with {@code R.style.Alp_42447968_Theme_*}. The reason is the themes contain
+ * resources that the library needs.</li>
+ * <li>With {@link #ACTION_COMPARE_PATTERN}, there are <b><i>4 possible result
+ * codes</i></b>: {@link android.app.Activity#RESULT_OK}, {@link android.app.Activity#RESULT_CANCELED},
+ * {@link #RESULT_FAILED} and {@link #RESULT_FORGOT_PATTERN}.</li>
+ * <li>With {@link #ACTION_VERIFY_CAPTCHA}, there are <b><i>3 possible result
+ * codes</i></b>: {@link android.app.Activity#RESULT_OK}, {@link android.app.Activity#RESULT_CANCELED},
+ * and {@link #RESULT_FAILED}.</li>
+ * </ul>
+ *
+ * @author Hai Bison
+ * @since v1.0
+ */
+public class LockPatternFragmentOld extends Fragment {
+
+ private static final String CLASSNAME = LockPatternFragmentOld.class.getName();
+
+ public static final String ACTION_CREATE_PATTERN = "create";
+
+ /**
+ * Use getSelectedMethod() to compare pattern. You provide the pattern to be
+ * compared with {@link #EXTRA_PATTERN}.
+ * <p/>
+ * If you enabled feature auto-save pattern before (with
+ * {@link com.haibison.android.lockpattern.util.Settings.Security#setAutoSavePattern(android.content.Context, boolean)} ),
+ * then you don't need {@link #EXTRA_PATTERN} at getActivity() time.
+ * <p/>
+ * You can use {@link #EXTRA_PENDING_INTENT_FORGOT_PATTERN} to help your
+ * users in case they forgot the patterns.
+ * <p/>
+ * If the user passes, {@link android.app.Activity#RESULT_OK} returns. If not,
+ * {@link #RESULT_FAILED} returns.
+ * <p/>
+ * If the user cancels the task, {@link android.app.Activity#RESULT_CANCELED} returns.
+ * <p/>
+ * In any case, there will have extra {@link #EXTRA_RETRY_COUNT} available
+ * in the intent result.
+ *
+ * @see #EXTRA_PATTERN
+ * @see #EXTRA_PENDING_INTENT_OK
+ * @see #EXTRA_PENDING_INTENT_CANCELLED
+ * @see #RESULT_FAILED
+ * @see #EXTRA_RETRY_COUNT
+ * @since v2.4 beta
+ */
+ public static final String ACTION_COMPARE_PATTERN = "authenticate";//CLASSNAME + ".compare_pattern";
+
+ /**
+ * Use getActivity() action to let the activity generate a random pattern and ask the
+ * user to re-draw it to verify.
+ * <p/>
+ * The default length of the auto-generated pattern is {@code 4}. You can
+ * change it with
+ * {@link com.haibison.android.lockpattern.util.Settings.Display#setCaptchaWiredDots(android.content.Context, int)}.
+ *
+ * @since v2.7 beta
+ */
+ public static final String ACTION_VERIFY_CAPTCHA = CLASSNAME + ".verify_captcha";
+
+ /**
+ * If you use {@link #ACTION_COMPARE_PATTERN} and the user fails to "login"
+ * after a number of tries, getActivity() activity will finish with getActivity() result code.
+ *
+ * @see #ACTION_COMPARE_PATTERN
+ * @see #EXTRA_RETRY_COUNT
+ */
+ public final int RESULT_FAILED = Activity.RESULT_FIRST_USER + 1;
+
+ /**
+ * If you use {@link #ACTION_COMPARE_PATTERN} and the user forgot his/ her
+ * pattern and decided to ask for your help with recovering the pattern (
+ * {@link #EXTRA_PENDING_INTENT_FORGOT_PATTERN}), getActivity() activity will finish
+ * with getActivity() result code.
+ *
+ * @see #ACTION_COMPARE_PATTERN
+ * @see #EXTRA_RETRY_COUNT
+ * @see #EXTRA_PENDING_INTENT_FORGOT_PATTERN
+ * @since v2.8 beta
+ */
+ public static final int RESULT_FORGOT_PATTERN = Activity.RESULT_FIRST_USER + 2;
+
+ /**
+ * For actions {@link #ACTION_COMPARE_PATTERN} and
+ * {@link #ACTION_VERIFY_CAPTCHA}, getActivity() key holds the number of tries that
+ * the user attempted to verify the input pattern.
+ */
+ public static final String EXTRA_RETRY_COUNT = CLASSNAME + ".retry_count";
+
+ /**
+ * Sets value of getActivity() key to a theme in {@code R.style.Alp_42447968_Theme_*}
+ * . Default is the one you set in your {@code AndroidManifest.xml}. Note
+ * that theme {@link R.style#Alp_42447968_Theme_Light_DarkActionBar} is
+ * available in API 4+, but it only works in API 14+.
+ *
+ * @since v1.5.3 beta
+ */
+ public static final String EXTRA_THEME = CLASSNAME + ".theme";
+
+ /**
+ * Key to hold the pattern. It must be a {@code char[]} array.
+ * <p/>
+ * <ul>
+ * <li>If you use encrypter, it should be an encrypted array.</li>
+ * <li>If you don't use encrypter, it should be the SHA-1 value of the
+ * actual pattern. You can generate the value by
+ * {@link com.haibison.android.lockpattern.widget.LockPatternUtils#patternToSha1(java.util.List)}.</li>
+ * </ul>
+ *
+ * @since v2 beta
+ */
+ public static final String EXTRA_PATTERN = CLASSNAME + ".pattern";
+
+ /**
+ * You can provide an {@link android.os.ResultReceiver} with getActivity() key. The activity
+ * will notify your receiver the same result code and intent data as you
+ * will receive them in {@link #onActivityResult(int, int, android.content.Intent)}.
+ *
+ * @since v2.4 beta
+ */
+ public static final String EXTRA_RESULT_RECEIVER = CLASSNAME
+ + ".result_receiver";
+
+ /**
+ * Put a {@link android.app.PendingIntent} into getActivity() key. It will be sent before
+ * {@link android.app.Activity#RESULT_OK} will be returning. If you were calling getActivity()
+ * activity with {@link #ACTION_CREATE_PATTERN}, key {@link #EXTRA_PATTERN}
+ * will be attached to the original intent which the pending intent holds.
+ *
+ * <h1>Notes</h1>
+ * <ul>
+ * <li>If you're going to use an activity, you don't need
+ * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library
+ * will call it inside {@link LockPatternFragmentOld} .</li>
+ * </ul>
+ */
+ public static final String EXTRA_PENDING_INTENT_OK = CLASSNAME
+ + ".pending_intent_ok";
+
+ /**
+ * Put a {@link android.app.PendingIntent} into getActivity() key. It will be sent before
+ * {@link android.app.Activity#RESULT_CANCELED} will be returning.
+ *
+ * <h1>Notes</h1>
+ * <ul>
+ * <li>If you're going to use an activity, you don't need
+ * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library
+ * will call it inside {@link LockPatternFragmentOld} .</li>
+ * </ul>
+ */
+ public static final String EXTRA_PENDING_INTENT_CANCELLED = CLASSNAME
+ + ".pending_intent_cancelled";
+
+ /**
+ * You put a {@link android.app.PendingIntent} into getActivity() extra. The library will show a
+ * button <i>"Forgot pattern?"</i> and call your intent later when the user
+ * taps it.
+ * <p/>
+ * <h1>Notes</h1>
+ * <ul>
+ * <li>If you use an activity, you don't need
+ * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library
+ * will call it inside {@link LockPatternFragmentOld} .</li>
+ * <li>{@link LockPatternFragmentOld} will finish with
+ * {@link #RESULT_FORGOT_PATTERN} <i><b>after</b> making a call</i> to start
+ * your pending intent.</li>
+ * <li>It is your responsibility to make sure the Intent is good. The
+ * library doesn't cover any errors when calling your intent.</li>
+ * </ul>
+ *
+ * @see #ACTION_COMPARE_PATTERN
+ * @since v2.8 beta
+ */
+ public static final String EXTRA_PENDING_INTENT_FORGOT_PATTERN = CLASSNAME
+ + ".pending_intent_forgot_pattern";
+
+ /**
+ * Helper enum for button OK commands. (Because we use only one "OK" button
+ * for different commands).
+ *
+ * @author Hai Bison
+ */
+ private static enum ButtonOkCommand {
+ CONTINUE,DONE
+ }// ButtonOkCommand
+
+ /**
+ * Delay time to reload the lock pattern view after a wrong pattern.
+ */
+ private static final long DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW = DateUtils.SECOND_IN_MILLIS;
+
+ /*
+ * FIELDS
+ */
+ private int mMaxRetries, mMinWiredDots, mRetryCount = 0, mCaptchaWiredDots;
+ private boolean mAutoSave, mStealthMode;
+ private IEncrypter mEncrypter;
+ private ButtonOkCommand mBtnOkCmd;
+ private Intent mIntentResult;
+
+ /*
+ * CONTROLS
+ */
+ private TextView mTextInfo;
+ private LockPatternView mLockPatternView;
+ private Button mBtnConfirm;
+
+ /*
+ * FRAGMENTS
+ */
+ private FragmentActivity fa;
+
+ /**
+ * Called when the activity is first created.
+ */
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+ fa = getActivity();
+
+ /*
+ * EXTRA_THEME
+ */
+ if (fa.getIntent().hasExtra(EXTRA_THEME))
+ fa.setTheme(fa.getIntent().getIntExtra(EXTRA_THEME,
+ R.style.Alp_42447968_Theme_Dark));
+ View view = inflater.inflate(R.layout.alp_42447968_lock_pattern_activity, container, false);
+ loadSettings();
+
+ mIntentResult = new Intent();
+ fa.setResult(Activity.RESULT_CANCELED, mIntentResult);
+ initContentView(view);
+ return view;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ }
+
+ /**
+ * Loads settings, either from manifest or {@link com.haibison.android.lockpattern.util.Settings}.
+ */
+ private void loadSettings() {
+ Bundle metaData = null;
+ try {
+ metaData = fa.getPackageManager().getActivityInfo(fa.getComponentName(),
+ PackageManager.GET_META_DATA).metaData;
+ } catch (NameNotFoundException e) {
+ /*
+ * Never catch getActivity().
+ */
+ e.printStackTrace();
+ }
+
+ if (metaData != null && metaData.containsKey(METADATA_MIN_WIRED_DOTS))
+ mMinWiredDots = Settings.Display.validateMinWiredDots(getActivity(),
+ metaData.getInt(METADATA_MIN_WIRED_DOTS));
+ else
+ mMinWiredDots = Settings.Display.getMinWiredDots(getActivity());
+
+ if (metaData != null && metaData.containsKey(METADATA_MAX_RETRIES))
+ mMaxRetries = Settings.Display.validateMaxRetries(getActivity(),
+ metaData.getInt(METADATA_MAX_RETRIES));
+ else
+ mMaxRetries = Settings.Display.getMaxRetries(getActivity());
+
+ if (metaData != null
+ && metaData.containsKey(METADATA_AUTO_SAVE_PATTERN))
+ mAutoSave = metaData.getBoolean(METADATA_AUTO_SAVE_PATTERN);
+ else
+ mAutoSave = Settings.Security.isAutoSavePattern(getActivity());
+
+ if (metaData != null
+ && metaData.containsKey(METADATA_CAPTCHA_WIRED_DOTS))
+ mCaptchaWiredDots = Settings.Display.validateCaptchaWiredDots(getActivity(),
+ metaData.getInt(METADATA_CAPTCHA_WIRED_DOTS));
+ else
+ mCaptchaWiredDots = Settings.Display.getCaptchaWiredDots(getActivity());
+
+ if (metaData != null && metaData.containsKey(METADATA_STEALTH_MODE))
+ mStealthMode = metaData.getBoolean(METADATA_STEALTH_MODE);
+ else
+ mStealthMode = Settings.Display.isStealthMode(getActivity());
+
+ /*
+ * Encrypter.
+ */
+ char[] encrypterClass;
+ if (metaData != null && metaData.containsKey(METADATA_ENCRYPTER_CLASS))
+ encrypterClass = metaData.getString(METADATA_ENCRYPTER_CLASS)
+ .toCharArray();
+ else
+ encrypterClass = Settings.Security.getEncrypterClass(getActivity());
+
+ if (encrypterClass != null) {
+ try {
+ mEncrypter = (IEncrypter) Class.forName(
+ new String(encrypterClass), false, fa.getClassLoader())
+ .newInstance();
+ } catch (Throwable t) {
+ throw new InvalidEncrypterException();
+ }
+ }
+ }
+
+ /**
+ * Initializes UI...
+ */
+ private void initContentView(View view) {
+
+ /*
+ * Save all controls' state to restore later.
+ */
+ CharSequence infoText = mTextInfo != null ? mTextInfo.getText() : null;
+ Boolean btnOkEnabled = mBtnConfirm != null ? mBtnConfirm.isEnabled()
+ : null;
+ DisplayMode lastDisplayMode = mLockPatternView != null ? mLockPatternView
+ .getDisplayMode() : null;
+ List<Cell> lastPattern = mLockPatternView != null ? mLockPatternView
+ .getPattern() : null;
+
+ UI.adjustDialogSizeForLargeScreens(fa.getWindow());
+
+ View mFooter;
+ Button mBtnCancel;
+
+ mTextInfo = (TextView) view.findViewById(R.id.alp_42447968_textview_info);
+ mLockPatternView = (LockPatternView) view.findViewById(R.id.alp_42447968_view_lock_pattern);
+
+ mFooter = view.findViewById(R.id.alp_42447968_viewgroup_footer);
+ mBtnCancel = (Button) view.findViewById(R.id.alp_42447968_button_cancel);
+ mBtnConfirm = (Button) view.findViewById(R.id.alp_42447968_button_confirm);
+
+ /*
+ * LOCK PATTERN VIEW
+ */
+
+ switch (getResources().getConfiguration().screenLayout
+ & Configuration.SCREENLAYOUT_SIZE_MASK) {
+ case Configuration.SCREENLAYOUT_SIZE_LARGE:
+ case Configuration.SCREENLAYOUT_SIZE_XLARGE: {
+ final int size = getResources().getDimensionPixelSize(
+ R.dimen.alp_42447968_lockpatternview_size);
+ LayoutParams lp = mLockPatternView.getLayoutParams();
+ lp.width = size;
+ lp.height = size;
+ mLockPatternView.setLayoutParams(lp);
+
+ break;
+ }
+ }
+
+ /*
+ * Haptic feedback.
+ */
+ boolean hapticFeedbackEnabled = false;
+ try {
+ hapticFeedbackEnabled = android.provider.Settings.System
+ .getInt(fa.getContentResolver(),
+ android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ 0) != 0;
+ } catch (Throwable t) {
+ /*
+ * Ignore it.
+ */
+ }
+ mLockPatternView.setTactileFeedbackEnabled(hapticFeedbackEnabled);
+
+ mLockPatternView.setInStealthMode(mStealthMode
+ && !ACTION_VERIFY_CAPTCHA.equals(fa.getIntent().getAction()));
+ mLockPatternView.setOnPatternListener(mLockPatternViewListener);
+ if (lastPattern != null && lastDisplayMode != null
+ && !ACTION_VERIFY_CAPTCHA.equals(fa.getIntent().getAction()))
+ mLockPatternView.setPattern(lastDisplayMode, lastPattern);
+ /*
+ * COMMAND BUTTONS
+ */
+
+ if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) {
+ mBtnCancel.setOnClickListener(mBtnCancelOnClickListener);
+ mBtnConfirm.setOnClickListener(mBtnConfirmOnClickListener);
+
+ mBtnCancel.setVisibility(View.VISIBLE);
+ mFooter.setVisibility(View.VISIBLE);
+ mTextInfo.setVisibility(View.VISIBLE);
+ if (infoText != null)
+ mTextInfo.setText(infoText);
+ else
+ mTextInfo //TODO nfc text glaube ich hier oder so
+ .setText(R.string.alp_42447968_msg_draw_an_unlock_pattern);
+
+ /*
+ * BUTTON OK
+ */
+ if (mBtnOkCmd == null)
+ mBtnOkCmd = ButtonOkCommand.CONTINUE;
+ switch (mBtnOkCmd) {
+ case CONTINUE:
+ mBtnConfirm.setText(R.string.alp_42447968_cmd_continue);
+ break;
+ case DONE:
+ mBtnConfirm.setText(R.string.alp_42447968_cmd_confirm);
+ break;
+ default:
+ break;
+ }
+ if (btnOkEnabled != null)
+ mBtnConfirm.setEnabled(btnOkEnabled);
+ }
+ else if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) {
+ if (TextUtils.isEmpty(infoText))
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock);
+ else
+ mTextInfo.setText(infoText);
+ if (fa.getIntent().hasExtra(EXTRA_PENDING_INTENT_FORGOT_PATTERN)) {
+ mBtnConfirm.setOnClickListener(mBtnConfirmOnClickListener);
+ mBtnConfirm.setText(R.string.alp_42447968_cmd_forgot_pattern);
+ mBtnConfirm.setEnabled(true);
+ mFooter.setVisibility(View.VISIBLE);
+ }
+ }
+ else if (ACTION_VERIFY_CAPTCHA.equals(fa.getIntent().getAction())) {
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
+
+ /*
+ * NOTE: EXTRA_PATTERN should hold a char[] array. In getActivity() case we
+ * use it as a temporary variable to hold a list of Cell.
+ */
+
+ final ArrayList<Cell> pattern;
+ if (fa.getIntent().hasExtra(EXTRA_PATTERN))
+ pattern = fa.getIntent()
+ .getParcelableArrayListExtra(EXTRA_PATTERN);
+ else
+ fa.getIntent().putParcelableArrayListExtra(
+ EXTRA_PATTERN,
+ pattern = LockPatternUtils
+ .genCaptchaPattern(mCaptchaWiredDots));
+
+ mLockPatternView.setPattern(DisplayMode.Animate, pattern);
+ }
+ }
+
+ /**
+ * Compares {@code pattern} to the given pattern (
+ * {@link #ACTION_COMPARE_PATTERN}) or to the generated "CAPTCHA" pattern (
+ * {@link #ACTION_VERIFY_CAPTCHA}). Then finishes the activity if they
+ * match.
+ *
+ * @param pattern
+ * the pattern to be compared.
+ */
+ private void doComparePattern(final List<Cell> pattern) {
+ if (pattern == null)
+ return;
+
+ /*
+ * Use a LoadingDialog because decrypting pattern might take time...
+ */
+ new LoadingDialog<Void, Void, Boolean>(getActivity(), false) {
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) {
+ char[] currentPattern = PassphraseWizardActivity.pattern;
+ if (currentPattern == null)
+ currentPattern = Settings.Security
+ .getPattern(getActivity());
+ if (currentPattern != null) {
+ if (mEncrypter != null) {
+ return pattern.equals(mEncrypter.decrypt(
+ getActivity(), currentPattern));
+ } else
+ return Arrays.equals(currentPattern,
+ LockPatternUtils.patternToSha1(pattern)
+ .toCharArray());
+ }
+ }
+ else if (ACTION_VERIFY_CAPTCHA.equals(fa.getIntent().getAction())) {
+ return pattern.equals(fa.getIntent()
+ .getParcelableArrayListExtra(EXTRA_PATTERN));
+ }
+ return false;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ super.onPostExecute(result);
+ if (result) {
+ Toast.makeText(getActivity(), "unlocked", Toast.LENGTH_SHORT).show();
+ finishWithResultOk(null);
+ }else {
+ mRetryCount++;
+ mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount);
+
+ if (mRetryCount >= mMaxRetries)
+ finishWithNegativeResult(RESULT_FAILED);
+ else {
+ mLockPatternView.setDisplayMode(DisplayMode.Wrong);
+ mTextInfo.setText(R.string.alp_42447968_msg_try_again);
+ mLockPatternView.postDelayed(mLockPatternViewReloader,
+ DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
+ }
+ }
+ }
+
+ }.execute();
+ }
+
+ /**
+ * Checks and creates the pattern.
+ *
+ * @param pattern
+ * the current pattern of lock pattern view.
+ */
+ private void doCheckAndCreatePattern(final List<Cell> pattern) {
+ if (pattern.size() < mMinWiredDots) {
+ mLockPatternView.setDisplayMode(DisplayMode.Wrong);
+ mTextInfo.setText(getResources().getQuantityString(
+ R.plurals.alp_42447968_pmsg_connect_x_dots, mMinWiredDots,
+ mMinWiredDots));
+ mLockPatternView.postDelayed(mLockPatternViewReloader,
+ DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
+ return;
+ }
+
+ if (fa.getIntent().hasExtra(EXTRA_PATTERN)) {
+ /*
+ * Use a LoadingDialog because decrypting pattern might take time...
+ */
+ new LoadingDialog<Void, Void, Boolean>(getActivity(), false) {
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ if (mEncrypter != null)
+ return pattern.equals(mEncrypter.decrypt(
+ getActivity(), fa.getIntent()
+ .getCharArrayExtra(EXTRA_PATTERN)));
+ else
+ return Arrays.equals(
+ fa.getIntent().getCharArrayExtra(EXTRA_PATTERN),
+ LockPatternUtils.patternToSha1(pattern)
+ .toCharArray());
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ super.onPostExecute(result);
+
+ if (result) {
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_your_new_unlock_pattern);
+ mBtnConfirm.setEnabled(true);
+ PassphraseWizardActivity.pattern = fa.getIntent()
+ .getCharArrayExtra(EXTRA_PATTERN);
+ } else {
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
+ mBtnConfirm.setEnabled(false);
+ mLockPatternView.setDisplayMode(DisplayMode.Wrong);
+ mLockPatternView.postDelayed(mLockPatternViewReloader,
+ DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
+ }
+ }
+ }.execute();
+ } else {
+ /*
+ * Use a LoadingDialog because encrypting pattern might take time...
+ */
+ new LoadingDialog<Void, Void, char[]>(getActivity(), false) {
+
+ @Override
+ protected char[] doInBackground(Void... params) {
+ return mEncrypter != null ? mEncrypter.encrypt(
+ getActivity(), pattern)
+ : LockPatternUtils.patternToSha1(pattern)
+ .toCharArray();
+ }
+
+ @Override
+ protected void onPostExecute(char[] result) {
+ super.onPostExecute(result);
+
+ fa.getIntent().putExtra(EXTRA_PATTERN, result);
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_pattern_recorded);
+ mBtnConfirm.setEnabled(true);
+ }
+
+ }.execute();
+ }
+ }
+
+ /**
+ * Finishes activity with {@link android.app.Activity#RESULT_OK}.
+ *
+ * @param pattern
+ * the pattern, if getActivity() is in mode creating pattern. In any
+ * cases, it can be set to {@code null}.
+ */
+ private void finishWithResultOk(char[] pattern) {
+ if (ACTION_CREATE_PATTERN.equals(getSelectedMethod()))
+ mIntentResult.putExtra(EXTRA_PATTERN, pattern);
+ else {
+ /*
+ * If the user was "logging in", minimum try count can not be zero.
+ */
+ mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount + 1);
+ }
+
+ fa.setResult(fa.RESULT_OK, mIntentResult);
+
+ /*
+ * ResultReceiver
+ */
+ ResultReceiver receiver = fa.getIntent().getParcelableExtra(
+ EXTRA_RESULT_RECEIVER);
+ if (receiver != null) {
+ Bundle bundle = new Bundle();
+ if (ACTION_CREATE_PATTERN.equals(getSelectedMethod()))
+ bundle.putCharArray(EXTRA_PATTERN, pattern);
+ else {
+ /*
+ * If the user was "logging in", minimum try count can not be
+ * zero.
+ */
+ bundle.putInt(EXTRA_RETRY_COUNT, mRetryCount + 1);
+ }
+ receiver.send(fa.RESULT_OK, bundle);
+ }
+
+ /*
+ * PendingIntent
+ */
+ PendingIntent pi = fa.getIntent().getParcelableExtra(
+ EXTRA_PENDING_INTENT_OK);
+ if (pi != null) {
+ try {
+ pi.send(getActivity(), fa.RESULT_OK, mIntentResult);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ fa.finish();
+ }
+
+ /**
+ * Finishes the activity with negative result (
+ * {@link android.app.Activity#RESULT_CANCELED}, {@link #RESULT_FAILED} or
+ * {@link #RESULT_FORGOT_PATTERN}).
+ */
+ private void finishWithNegativeResult(int resultCode) {
+ if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod()))
+ mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount);
+
+ fa.setResult(resultCode, mIntentResult);
+
+ /*
+ * ResultReceiver
+ */
+ ResultReceiver receiver = fa.getIntent().getParcelableExtra(
+ EXTRA_RESULT_RECEIVER);
+ if (receiver != null) {
+ Bundle resultBundle = null;
+ if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) {
+ resultBundle = new Bundle();
+ resultBundle.putInt(EXTRA_RETRY_COUNT, mRetryCount);
+ }
+ receiver.send(resultCode, resultBundle);
+ }
+
+ /*
+ * PendingIntent
+ */
+ PendingIntent pi = fa.getIntent().getParcelableExtra(
+ EXTRA_PENDING_INTENT_CANCELLED);
+ if (pi != null) {
+ try {
+ pi.send(getActivity(), resultCode, mIntentResult);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ fa.finish();
+ }
+
+ /*
+ * LISTENERS
+ */
+
+ private final LockPatternView.OnPatternListener mLockPatternViewListener = new LockPatternView.OnPatternListener() {
+
+ @Override
+ public void onPatternStart() {
+ mLockPatternView.removeCallbacks(mLockPatternViewReloader);
+ mLockPatternView.setDisplayMode(DisplayMode.Correct);
+
+ if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) {
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_release_finger_when_done);
+ mBtnConfirm.setEnabled(false);
+ if (mBtnOkCmd == ButtonOkCommand.CONTINUE)
+ fa.getIntent().removeExtra(EXTRA_PATTERN);
+ }
+ else if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) {
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock);
+ }
+ else if (ACTION_VERIFY_CAPTCHA.equals(getSelectedMethod())) {
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
+ }
+ }
+
+ @Override
+ public void onPatternDetected(List<Cell> pattern) {
+ if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) {
+ doCheckAndCreatePattern(pattern);
+ }
+ else if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) {
+ doComparePattern(pattern);
+ }
+ else if (ACTION_VERIFY_CAPTCHA.equals(getSelectedMethod())) {
+ if (!DisplayMode.Animate.equals(mLockPatternView
+ .getDisplayMode()))
+ doComparePattern(pattern);
+ }
+ }
+
+ @Override
+ public void onPatternCleared() {
+ mLockPatternView.removeCallbacks(mLockPatternViewReloader);
+
+ if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) {
+ mLockPatternView.setDisplayMode(DisplayMode.Correct);
+ mBtnConfirm.setEnabled(false);
+ if (mBtnOkCmd == ButtonOkCommand.CONTINUE) {
+ fa.getIntent().removeExtra(EXTRA_PATTERN);
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_draw_an_unlock_pattern);
+ } else
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
+ }
+ else if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) {
+ mLockPatternView.setDisplayMode(DisplayMode.Correct);
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock);
+ }
+ else if (ACTION_VERIFY_CAPTCHA.equals(fa.getIntent().getAction())) {
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
+ List<Cell> pattern = fa.getIntent().getParcelableArrayListExtra(
+ EXTRA_PATTERN);
+ mLockPatternView.setPattern(DisplayMode.Animate, pattern);
+ }
+ }
+
+ @Override
+ public void onPatternCellAdded(List<Cell> pattern) {
+ }
+ };
+
+ private final View.OnClickListener mBtnCancelOnClickListener = new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ finishWithNegativeResult(fa.RESULT_CANCELED);
+ }
+ };
+
+ private final View.OnClickListener mBtnConfirmOnClickListener = new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) {
+ if (mBtnOkCmd == ButtonOkCommand.CONTINUE) {
+ mBtnOkCmd = ButtonOkCommand.DONE;
+ mLockPatternView.clearPattern();
+ mTextInfo
+ .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
+ mBtnConfirm.setText(R.string.alp_42447968_cmd_confirm);
+ mBtnConfirm.setEnabled(false);
+ } else {
+ final char[] pattern = fa.getIntent().getCharArrayExtra(
+ EXTRA_PATTERN);
+ if (mAutoSave)
+ Settings.Security.setPattern(getActivity(),
+ pattern);
+ finishWithResultOk(pattern);
+ }
+ }
+ else if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) {
+ /*
+ * We don't need to verify the extra. First, getActivity() button is only
+ * visible if there is getActivity() extra in the intent. Second, it is
+ * the responsibility of the caller to make sure the extra is
+ * good.
+ */
+ PendingIntent pi;
+ try {
+ pi = fa.getIntent().getParcelableExtra(
+ EXTRA_PENDING_INTENT_FORGOT_PATTERN);
+ pi.send();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ finishWithNegativeResult(RESULT_FORGOT_PATTERN);
+ }
+ }
+ };
+
+ /**
+ * getActivity() reloads the {@link #mLockPatternView} after a wrong pattern.
+ */
+ private final Runnable mLockPatternViewReloader = new Runnable() {
+
+ @Override
+ public void run() {
+ mLockPatternView.clearPattern();
+ mLockPatternViewListener.onPatternCleared();
+ }
+ };
+
+ /**
+ * Fragment constructor allowing to add a bundle with all necessary information to the fragment
+ * @param method contains information about which method to choose (set
+ * @return LockPatternFragment with bundle
+ */
+ public static LockPatternFragmentOld newInstance(String method){
+ LockPatternFragmentOld fragment = new LockPatternFragmentOld();
+ Bundle args = new Bundle();
+ args.putString("ACTION", method);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ /**
+ * Getter for the method string saved in fragment arguments
+ * @return String telling which method was selected
+ */
+ public String getSelectedMethod () {
+ return getArguments().getString("ACTION");
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
index 6965ca7cb..cd236dd57 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
@@ -99,6 +99,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
return GNU_DUMMY;
case 2:
return PASSPHRASE;
+// return PATTERN;
case 3:
return PASSPHRASE_EMPTY;
case 4:
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
index 7acd62c72..2c4834e02 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -382,29 +382,32 @@ public class EditKeyFragment extends LoaderFragment implements
}
private void changePassphrase() {
+ Intent passIntent = new Intent(getActivity(), PassphraseWizardActivity.class);
+ passIntent.setAction(PassphraseWizardActivity.CREATE_METHOD);
+ startActivityForResult(passIntent, 12);
// Message is received after passphrase is cached
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) {
- Bundle data = message.getData();
-
- // cache new returned passphrase!
- mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel(
- data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE),
- null
- );
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
-
- SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance(
- messenger, mCurrentPassphrase, R.string.title_change_passphrase);
-
- setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog");
+// Handler returnHandler = new Handler() {
+// @Override
+// public void handleMessage(Message message) {
+// if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) {
+// Bundle data = message.getData();
+//
+// // cache new returned passphrase!
+// mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel(
+// data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE),
+// null
+// );
+// }
+// }
+// };
+//
+// // Create a new Messenger for the communication back
+// Messenger messenger = new Messenger(returnHandler);
+//
+// SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance(
+// messenger, mCurrentPassphrase, R.string.title_change_passphrase);
+//
+// setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog");
}
private void editUserId(final int position) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java
new file mode 100644
index 000000000..93778fd0c
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import android.annotation.TargetApi;
+import android.app.AlertDialog;
+import android.app.PendingIntent;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.nfc.FormatException;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+import android.nfc.Tag;
+import android.nfc.tech.Ndef;
+import android.os.Build;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.haibison.android.lockpattern.LockPatternFragment;
+import com.haibison.android.lockpattern.LockPatternFragmentOld;
+import com.haibison.android.lockpattern.widget.LockPatternView;
+
+import org.sufficientlysecure.keychain.R;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.List;
+
+@TargetApi(Build.VERSION_CODES.HONEYCOMB)
+public class PassphraseWizardActivity extends FragmentActivity implements LockPatternView.OnPatternListener {
+ //create or authenticate
+ public String selectedAction;
+ //for lockpattern
+ public static char[] pattern;
+ private static String passphrase = "";
+ //nfc string
+ private static byte[] output = new byte[8];
+
+ public static final String CREATE_METHOD = "create";
+ public static final String AUTHENTICATION = "authenticate";
+
+ NfcAdapter adapter;
+ PendingIntent pendingIntent;
+ IntentFilter writeTagFilters[];
+ boolean writeMode;
+ Tag myTag;
+ boolean writeNFC = false;
+ boolean readNFC = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getActionBar() != null) {
+ getActionBar().setTitle(R.string.unlock_method);
+ }
+
+ selectedAction = getIntent().getAction();
+ if (savedInstanceState == null) {
+ SelectMethods selectMethods = new SelectMethods();
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.add(R.id.fragmentContainer, selectMethods).commit();
+ }
+ setContentView(R.layout.passphrase_wizard);
+
+ adapter = NfcAdapter.getDefaultAdapter(this);
+ if (adapter != null) {
+ pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, PassphraseWizardActivity.class).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
+ IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
+ tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
+ writeTagFilters = new IntentFilter[]{tagDetected};
+ }
+ }
+
+ public void noPassphrase(View view) {
+ passphrase = "";
+ Toast.makeText(this, R.string.no_passphrase_set, Toast.LENGTH_SHORT).show();
+ this.finish();
+ }
+
+ public void passphrase(View view) {
+ Passphrase passphrase = new Passphrase();
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fragmentContainer, passphrase).addToBackStack(null).commit();
+ }
+
+ public void startLockpattern(View view) {
+ if (getActionBar() != null) {
+ getActionBar().setTitle(R.string.draw_lockpattern);
+ }
+// LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction);
+ LockPatternFragment lpf = LockPatternFragment.newInstance("asd");
+
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit();
+ }
+
+ public void cancel(View view) {
+ this.finish();
+ }
+
+ public void savePassphrase(View view) {
+ EditText passphrase = (EditText) findViewById(R.id.passphrase);
+ passphrase.setError(null);
+ String pw = passphrase.getText().toString();
+ //check and save passphrase
+ if (selectedAction.equals(CREATE_METHOD)) {
+ EditText passphraseAgain = (EditText) findViewById(R.id.passphraseAgain);
+ passphraseAgain.setError(null);
+ String pwAgain = passphraseAgain.getText().toString();
+
+ if (!TextUtils.isEmpty(pw)) {
+ if (!TextUtils.isEmpty(pwAgain)) {
+ if (pw.equals(pwAgain)) {
+ PassphraseWizardActivity.passphrase = pw;
+ Toast.makeText(this, getString(R.string.passphrase_saved), Toast.LENGTH_SHORT).show();
+ this.finish();
+ } else {
+ passphrase.setError(getString(R.string.passphrase_invalid));
+ passphrase.requestFocus();
+ }
+ } else {
+ passphraseAgain.setError(getString(R.string.missing_passphrase));
+ passphraseAgain.requestFocus();
+ }
+ } else {
+ passphrase.setError(getString(R.string.missing_passphrase));
+ passphrase.requestFocus();
+ }
+ }
+ //check for right passphrase
+ if (selectedAction.equals(AUTHENTICATION)) {
+ if (pw.equals(PassphraseWizardActivity.passphrase)) {
+ Toast.makeText(this, getString(R.string.unlocked), Toast.LENGTH_SHORT).show();
+ this.finish();
+ } else {
+ passphrase.setError(getString(R.string.passphrase_invalid));
+ passphrase.requestFocus();
+ }
+ }
+ }
+
+ public void NFC(View view) {
+ if (adapter != null) {
+ if (getActionBar() != null) {
+ getActionBar().setTitle(R.string.nfc_title);
+ }
+ NFCFragment nfc = new NFCFragment();
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fragmentContainer, nfc).addToBackStack(null).commit();
+
+ //if you want to create a new method or just authenticate
+ if (CREATE_METHOD.equals(selectedAction)) {
+ writeNFC = true;
+ } else if (AUTHENTICATION.equals(selectedAction)) {
+ readNFC = true;
+ }
+
+ if (!adapter.isEnabled()) {
+ showAlertDialog(getString(R.string.enable_nfc), true);
+ }
+ } else {
+ showAlertDialog(getString(R.string.no_nfc_support), false);
+ }
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
+ myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
+
+ if (writeNFC && CREATE_METHOD.equals(selectedAction)) {
+ //write new password on NFC tag
+ try {
+ if (myTag != null) {
+ write(myTag);
+ writeNFC = false; //just write once
+ Toast.makeText(this, R.string.nfc_write_succesful, Toast.LENGTH_SHORT).show();
+ //advance to lockpattern
+ LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction);
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (FormatException e) {
+ e.printStackTrace();
+ }
+
+ } else if (readNFC && AUTHENTICATION.equals(selectedAction)) {
+ //read pw from NFC tag
+ try {
+ if (myTag != null) {
+ //if tag detected, read tag
+ String pwtag = read(myTag);
+ if (output != null && pwtag.equals(output.toString())) {
+
+ //passwort matches, go to next view
+ Toast.makeText(this, R.string.passphrases_match + "!", Toast.LENGTH_SHORT).show();
+
+ LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction);
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit();
+ readNFC = false; //just once
+ } else {
+ //passwort doesnt match
+ TextView nfc = (TextView) findViewById(R.id.nfcText);
+ nfc.setText(R.string.nfc_wrong_tag);
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (FormatException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ private void write(Tag tag) throws IOException, FormatException {
+ //generate new random key and write them on the tag
+ SecureRandom sr = new SecureRandom();
+ sr.nextBytes(output);
+ NdefRecord[] records = {createRecord(output.toString())};
+ NdefMessage message = new NdefMessage(records);
+ Ndef ndef = Ndef.get(tag);
+ ndef.connect();
+ ndef.writeNdefMessage(message);
+ ndef.close();
+ }
+
+ private String read(Tag tag) throws IOException, FormatException {
+ //read string from tag
+ String password = null;
+ Ndef ndef = Ndef.get(tag);
+ ndef.connect();
+ NdefMessage ndefMessage = ndef.getCachedNdefMessage();
+
+ NdefRecord[] records = ndefMessage.getRecords();
+ for (NdefRecord ndefRecord : records) {
+ if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {
+ try {
+ password = readText(ndefRecord);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ ndef.close();
+ return password;
+ }
+
+ private String readText(NdefRecord record) throws UnsupportedEncodingException {
+ //low-level method for reading nfc
+ byte[] payload = record.getPayload();
+ String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16";
+ int languageCodeLength = payload[0] & 0063;
+ return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
+ }
+
+ private NdefRecord createRecord(String text) throws UnsupportedEncodingException {
+ //low-level method for writing nfc
+ String lang = "en";
+ byte[] textBytes = text.getBytes();
+ byte[] langBytes = lang.getBytes("US-ASCII");
+ int langLength = langBytes.length;
+ int textLength = textBytes.length;
+ byte[] payload = new byte[1 + langLength + textLength];
+
+ // set status byte (see NDEF spec for actual bits)
+ payload[0] = (byte) langLength;
+ // copy langbytes and textbytes into payload
+ System.arraycopy(langBytes, 0, payload, 1, langLength);
+ System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);
+ return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
+ }
+
+ public void showAlertDialog(String message, boolean nfc) {
+ //This method shows an AlertDialog
+ AlertDialog.Builder alert = new AlertDialog.Builder(this);
+ alert.setTitle("Information").setMessage(message).setPositiveButton("Ok",
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ }
+ }
+ );
+ if (nfc) {
+
+ alert.setNeutralButton(R.string.nfc_settings,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialogInterface, int i) {
+ startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
+ }
+ }
+ );
+ }
+ alert.show();
+ }
+
+ @Override
+ public void onPause() {
+ //pause this app and free nfc intent
+ super.onPause();
+ if (adapter != null) {
+ WriteModeOff();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ //resume this app and get nfc intent
+ super.onResume();
+ if (adapter != null) {
+ WriteModeOn();
+ }
+ }
+
+ private void WriteModeOn() {
+ //enable nfc for this view
+ writeMode = true;
+ adapter.enableForegroundDispatch(this, pendingIntent, writeTagFilters, null);
+ }
+
+ private void WriteModeOff() {
+ //disable nfc for this view
+ writeMode = false;
+ adapter.disableForegroundDispatch(this);
+ }
+
+ @Override
+ public void onPatternStart() {
+
+ }
+
+ @Override
+ public void onPatternCleared() {
+
+ }
+
+ @Override
+ public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
+
+ }
+
+ @Override
+ public void onPatternDetected(List<LockPatternView.Cell> pattern) {
+
+ }
+
+ public static class SelectMethods extends Fragment {
+// private OnFragmentInteractionListener mListener;
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ */
+ public SelectMethods() {
+
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (getActivity().getActionBar() != null) {
+ getActivity().getActionBar().setTitle(R.string.unlock_method);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.passphrase_wizard_fragment_select_methods, container, false);
+ }
+
+// @Override
+// public void onAttach(Activity activity) {
+// super.onAttach(activity);
+// try {
+// mListener = (OnFragmentInteractionListener) activity;
+// } catch (ClassCastException e) {
+// throw new ClassCastException(activity.toString()
+// + " must implement OnFragmentInteractionListener");
+// }
+// }
+//
+// @Override
+// public void onDetach() {
+// super.onDetach();
+// mListener = null;
+// }
+
+ /**
+ * This interface must be implemented by activities that contain this
+ * fragment to allow an interaction in this fragment to be communicated
+ * to the activity and potentially other fragments contained in that
+ * activity.
+ * <p/>
+ * See the Android Training lesson <a href=
+ * "http://developer.android.com/training/basics/fragments/communicating.html"
+ * >Communicating with Other Fragments</a> for more information.
+ */
+// public static interface OnFragmentInteractionListener {
+// public void onFragmentInteraction(Uri uri);
+// }
+
+ }
+
+
+ // /**
+// * A simple {@link android.support.v4.app.Fragment} subclass.
+// * Activities that contain this fragment must implement the
+// * {@link com.haibison.android.lockpattern.Passphrase.OnFragmentInteractionListener} interface
+// * to handle interaction events.
+// */
+ public static class Passphrase extends Fragment {
+
+// private OnFragmentInteractionListener mListener;
+
+ public Passphrase() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View view = inflater.inflate(R.layout.passphrase_wizard_fragment_passphrase, container, false);
+ EditText passphraseAgain = (EditText) view.findViewById(R.id.passphraseAgain);
+ TextView passphraseText = (TextView) view.findViewById(R.id.passphraseText);
+ TextView passphraseTextAgain = (TextView) view.findViewById(R.id.passphraseTextAgain);
+ String selectedAction = getActivity().getIntent().getAction();
+ if (selectedAction.equals(AUTHENTICATION)) {
+ passphraseAgain.setVisibility(View.GONE);
+ passphraseTextAgain.setVisibility(View.GONE);
+ passphraseText.setText(R.string.enter_passphrase);
+// getActivity().getActionBar().setTitle(R.string.enter_passphrase);
+ } else if (selectedAction.equals(CREATE_METHOD)) {
+ passphraseAgain.setVisibility(View.VISIBLE);
+ passphraseTextAgain.setVisibility(View.VISIBLE);
+ passphraseText.setText(R.string.passphrase);
+// getActivity().getActionBar().setTitle(R.string.set_passphrase);
+ }
+ return view;
+ }
+
+// @Override
+// public void onAttach(Activity activity) {
+// super.onAttach(activity);
+// try {
+// mListener = (OnFragmentInteractionListener) activity;
+// } catch (ClassCastException e) {
+// throw new ClassCastException(activity.toString()
+// + " must implement OnFragmentInteractionListener");
+// }
+// }
+//
+// @Override
+// public void onDetach() {
+// super.onDetach();
+// mListener = null;
+// }
+
+// /**
+// * This interface must be implemented by activities that contain this
+// * fragment to allow an interaction in this fragment to be communicated
+// * to the activity and potentially other fragments contained in that
+// * activity.
+// * <p/>
+// * See the Android Training lesson <a href=
+// * "http://developer.android.com/training/basics/fragments/communicating.html"
+// * >Communicating with Other Fragments</a> for more information.
+// */
+// public interface OnFragmentInteractionListener {
+// public void onFragmentInteraction(Uri uri);
+// }
+ }
+
+
+ /**
+ * A simple {@link android.support.v4.app.Fragment} subclass.
+ * Activities that contain this fragment must implement the
+ * interface
+ * to handle interaction events.
+ * Use the method to
+ * create an instance of this fragment.
+ */
+ public static class NFCFragment extends Fragment {
+ // TODO: Rename parameter arguments, choose names that match
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ private static final String ARG_PARAM1 = "param1";
+ private static final String ARG_PARAM2 = "param2";
+
+ // TODO: Rename and change types of parameters
+ private String mParam1;
+ private String mParam2;
+
+// private OnFragmentInteractionListener mListener;
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param param1 Parameter 1.
+ * @param param2 Parameter 2.
+ * @return A new instance of fragment SelectMethods.
+ */
+ // TODO: Rename and change types and number of parameters
+ public static NFCFragment newInstance(String param1, String param2) {
+ NFCFragment fragment = new NFCFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_PARAM1, param1);
+ args.putString(ARG_PARAM2, param2);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ public NFCFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ mParam1 = getArguments().getString(ARG_PARAM1);
+ mParam2 = getArguments().getString(ARG_PARAM2);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.passphrase_wizard_fragment_nfc, container, false);
+ }
+
+// // TODO: Rename method, update argument and hook method into UI event
+// public void onButtonPressed(Uri uri) {
+// if (mListener != null) {
+// mListener.onFragmentInteraction(uri);
+// }
+// }
+
+// @Override
+// public void onAttach(Activity activity) {
+// super.onAttach(activity);
+// try {
+// mListener = (OnFragmentInteractionListener) activity;
+// } catch (ClassCastException e) {
+// throw new ClassCastException(activity.toString()
+// + " must implement OnFragmentInteractionListener");
+// }
+// }
+
+
+// @Override
+// public void onDetach() {
+// super.onDetach();
+// mListener = null;
+// }
+ }
+
+}
diff --git a/OpenKeychain/src/main/res/drawable/nfc.png b/OpenKeychain/src/main/res/drawable/nfc.png
new file mode 100644
index 000000000..f28b043bc
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable/nfc.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/layout/alp_42447968_lock_pattern_fragment.xml b/OpenKeychain/src/main/res/layout/alp_42447968_lock_pattern_fragment.xml
new file mode 100644
index 000000000..6a154fa55
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/alp_42447968_lock_pattern_fragment.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/topLayout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <com.haibison.android.lockpattern.widget.LockPatternView_v14
+ android:id="@+id/lockPattern"
+ android:layout_width="@dimen/alp_42447968_separator_size"
+ android:layout_height="@dimen/alp_42447968_separator_size"
+ android:layout_marginTop="@dimen/alp_42447968_separator_size"
+ android:layout_marginBottom="@dimen/alp_42447968_separator_size"
+ android:layout_gravity="center_horizontal" />
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/passphrase_wizard.xml b/OpenKeychain/src/main/res/layout/passphrase_wizard.xml
new file mode 100644
index 000000000..efc65b7c7
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/passphrase_wizard.xml
@@ -0,0 +1,11 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/fragmentContainer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_nfc.xml b/OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_nfc.xml
new file mode 100644
index 000000000..46d430c4e
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_nfc.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="16dp">
+
+ <TextView
+ android:id="@+id/nfcText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:text="@string/nfc_text"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:lines="2" />
+
+
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/imageView"
+ android:padding="16dp"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:src="@drawable/nfc"
+ android:adjustViewBounds="true" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_passphrase.xml b/OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_passphrase.xml
new file mode 100644
index 000000000..61bd4572d
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_passphrase.xml
@@ -0,0 +1,109 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="16dp"
+ android:orientation="vertical"
+ tools:context="pSontag.testopenkeychain.Passphrase">
+
+
+
+ <TableLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TableRow
+ android:layout_marginBottom="10dp">
+ <TextView
+ android:id="@+id/passphraseText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_span="2"
+ android:padding="8dp"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/passphrase"
+ android:layout_weight="1"/>
+ </TableRow>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <TableRow>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/passphrase"/>
+ <EditText
+ android:id="@+id/passphrase"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textPassword"
+ android:padding="8dp"
+ android:layout_weight="6"/>
+
+ </TableRow>
+
+ <TableRow
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="10dp">
+ <TextView
+ android:id="@+id/passphraseTextAgain"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:text="@string/passphrase_again"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_weight="1"/>
+ <EditText
+ android:id="@+id/passphraseAgain"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textPassword"
+ android:imeOptions="actionDone"
+ android:padding="8dp"
+ android:layout_weight="6"/>
+
+ </TableRow>
+ </TableLayout>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Cancel"
+ android:onClick="cancel"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ style="?attr/alp_42447968_button_bar_button_style"/>
+ <View
+ android:layout_width="1dip"
+ android:layout_height="50dip"
+ android:background="?android:attr/listDivider" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Ok"
+ android:onClick="savePassphrase"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ style="?attr/alp_42447968_button_bar_button_style"/>
+
+ </LinearLayout>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_select_methods.xml b/OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_select_methods.xml
new file mode 100644
index 000000000..42baa6a0d
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/passphrase_wizard_fragment_select_methods.xml
@@ -0,0 +1,89 @@
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="16dp"
+ tools:context="pSontag.testopenkeychain.SelectMethods">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:padding="8dp"
+ android:text="@string/title_unlock_method"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:id="@+id/selectNoPassphrase"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:text="@string/noPassphrase"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:padding="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:clickable="true"
+ android:onClick="noPassphrase"
+ style="@style/SelectableItem"/>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:id="@+id/selectPassphrase"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:text="@string/passphrase"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:padding="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:clickable="true"
+ android:onClick="passphrase"
+ style="@style/SelectableItem"/>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+ <TextView
+ android:id="@+id/selectLockpattern"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:text="@string/lockpattern"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:padding="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:clickable="true"
+ android:onClick="startLockpattern"
+ style="@style/SelectableItem"/>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+ <TextView
+ android:id="@+id/selectLockpatternNFC"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:text="@string/lockpatternNFC"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:padding="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:clickable="true"
+ android:onClick="NFC"
+ style="@style/SelectableItem"/>
+
+ </LinearLayout>
+</ScrollView>
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 8dc708f1c..d9182a548 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -1072,4 +1072,31 @@
<string name="exchange_description">"To start a key exchange, choose the number of participants on the right side, then hit the “Start exchange” button.\n\nYou will be asked two more questions to make sure only the right participants are in the exchange and their fingerprints are correct."</string>
<string name="user_id_none"><![CDATA[<none>]]></string>
+ <!-- Passphrase wizard -->
+ <!-- TODO: rename all the things! -->
+ <string name="title_unlock_method">Choose an unlock method</string>
+ <!--<string name="enter_passphrase_twice">Enter passphrase twice</string>-->
+ <string name="enter_passphrase">Enter passphrase</string>
+ <string name="passphrase">Passphrase</string>
+ <string name="noPassphrase">No passphrase</string>
+ <string name="no_passphrase_set">No passphrase set</string>
+ <string name="passphrases_match">Passphrases do match</string>
+ <string name="passphrase_saved">Passphrase saved</string>
+ <string name="passphrase_invalid">Passphrase invalid</string>
+ <string name="missing_passphrase">Missing passphrase</string>
+ <string name="passphrase_again">Again</string>
+ <string name="lockpattern">Lockpattern</string>
+ <string name="lockpatternNFC">NFC + Lockpattern</string>
+ <string name="unlock_method">Unlock method</string>
+ <string name="set_passphrase">Set passphrase</string>
+ <string name="draw_lockpattern">Draw lockpattern</string>
+ <string name="nfc_title">NFC</string>
+ <!--<string name="nfc_text">Please place a NFC tag near your device</string>-->
+ <string name="nfc_wrong_tag">Wrong Tag. Please try again.</string>
+ <string name="enable_nfc">Please activate NFC in your settings</string>
+ <string name="no_nfc_support">This device does not support NFC</string>
+ <string name="nfc_write_succesful">Successfully written on NFC tag</string>
+ <string name="unlocked">Unlocked</string>
+ <string name="nfc_settings">Settings</string>
+
</resources>