Passphrase wizard tests

This commit is contained in:
Dominik Schürmann
2015-01-06 14:52:07 +01:00
parent ccde6add70
commit e34ad18ed2
13 changed files with 1891 additions and 22 deletions

View File

@@ -665,6 +665,8 @@
android:configChanges="orientation|screenSize|keyboard|keyboardHidden" android:configChanges="orientation|screenSize|keyboard|keyboardHidden"
android:screenOrientation="user" android:screenOrientation="user"
android:theme="@style/Alp.42447968.Theme.Dialog.Light" /> android:theme="@style/Alp.42447968.Theme.Dialog.Light" />
<activity
android:name=".ui.PassphraseWizardActivity" />
<!-- <!--
NOTE: singleTop is set to get NFC foreground dispatch to work. NOTE: singleTop is set to get NFC foreground dispatch to work.
Then, all NFC intents will be broadcasted to onNewIntent() of this activity! Then, all NFC intents will be broadcasted to onNewIntent() of this activity!

View File

@@ -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;
}
}

View File

@@ -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");
}
}

View File

@@ -98,6 +98,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
return GNU_DUMMY; return GNU_DUMMY;
case 2: case 2:
return PASSPHRASE; return PASSPHRASE;
// return PATTERN;
case 3: case 3:
return PASSPHRASE_EMPTY; return PASSPHRASE_EMPTY;
case 4: case 4:

View File

@@ -382,29 +382,32 @@ public class EditKeyFragment extends LoaderFragment implements
} }
private void changePassphrase() { 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 // Message is received after passphrase is cached
Handler returnHandler = new Handler() { // Handler returnHandler = new Handler() {
@Override // @Override
public void handleMessage(Message message) { // public void handleMessage(Message message) {
if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) { // if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) {
Bundle data = message.getData(); // Bundle data = message.getData();
//
// cache new returned passphrase! // // cache new returned passphrase!
mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel( // mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel(
data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE), // data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE),
null // null
); // );
} // }
} // }
}; // };
//
// Create a new Messenger for the communication back // // Create a new Messenger for the communication back
Messenger messenger = new Messenger(returnHandler); // Messenger messenger = new Messenger(returnHandler);
//
SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance( // SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance(
messenger, mCurrentPassphrase, R.string.title_change_passphrase); // messenger, mCurrentPassphrase, R.string.title_change_passphrase);
//
setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog"); // setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog");
} }
private void editUserId(final int position) { private void editUserId(final int position) {

View File

@@ -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;
// }
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1054,4 +1054,31 @@
<string name="first_time_import_key">"Import from file"</string> <string name="first_time_import_key">"Import from file"</string>
<string name="first_time_skip">"Skip Setup"</string> <string name="first_time_skip">"Skip Setup"</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> </resources>