From e34ad18ed26166751f6897169056044c2d19ce67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 6 Jan 2015 14:52:07 +0100 Subject: Passphrase wizard tests --- .../android/lockpattern/LockPatternFragment.java | 55 ++ .../lockpattern/LockPatternFragmentOld.java | 926 +++++++++++++++++++++ .../keychain/pgp/CanonicalizedSecretKey.java | 1 + .../keychain/ui/EditKeyFragment.java | 47 +- .../keychain/ui/PassphraseWizardActivity.java | 602 ++++++++++++++ 5 files changed, 1609 insertions(+), 22 deletions(-) create mode 100644 OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragment.java create mode 100644 OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragmentOld.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java (limited to 'OpenKeychain/src/main/java') 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. + *

+ * 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. + *

+ * + *

NOTES

+ * + * + * @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}. + *

+ * 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. + *

+ * You can use {@link #EXTRA_PENDING_INTENT_FORGOT_PATTERN} to help your + * users in case they forgot the patterns. + *

+ * If the user passes, {@link android.app.Activity#RESULT_OK} returns. If not, + * {@link #RESULT_FAILED} returns. + *

+ * If the user cancels the task, {@link android.app.Activity#RESULT_CANCELED} returns. + *

+ * 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. + *

+ * 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. + *

+ *

+ * + * @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. + * + *

Notes

+ * + */ + 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. + * + *

Notes

+ * + */ + 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 "Forgot pattern?" and call your intent later when the user + * taps it. + *

+ *

Notes

+ * + * + * @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 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 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 pattern) { + if (pattern == null) + return; + + /* + * Use a LoadingDialog because decrypting pattern might take time... + */ + new LoadingDialog(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 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(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(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 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 pattern = fa.getIntent().getParcelableArrayListExtra( + EXTRA_PATTERN); + mLockPatternView.setPattern(DisplayMode.Animate, pattern); + } + } + + @Override + public void onPatternCellAdded(List 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 a965d4819..fa7460915 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -98,6 +98,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 + * + * 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 . + */ + +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 pattern) { + + } + + @Override + public void onPatternDetected(List 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. + *

+ * See the Android Training lesson Communicating with Other Fragments 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. +// *

+// * See the Android Training lesson Communicating with Other Fragments 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; +// } + } + +} -- cgit v1.2.3