diff --git a/MasterPassword/Java/masterpassword-android/res/layout/activity_emergency.xml b/MasterPassword/Java/masterpassword-android/res/layout/activity_emergency.xml
index 4d578ce4..37c89004 100644
--- a/MasterPassword/Java/masterpassword-android/res/layout/activity_emergency.xml
+++ b/MasterPassword/Java/masterpassword-android/res/layout/activity_emergency.xml
@@ -108,7 +108,7 @@
android:gravity="center"
android:background="@android:color/transparent"
android:textColor="#FFFFFF"
- android:textSize="32sp"
+ android:textSize="28sp"
tools:text="LuxdZozvDuma4["
android:onClick="copySitePassword" />
diff --git a/MasterPassword/Java/masterpassword-android/res/values/strings.xml b/MasterPassword/Java/masterpassword-android/res/values/strings.xml
index ffd4b787..efc25fd9 100644
--- a/MasterPassword/Java/masterpassword-android/res/values/strings.xml
+++ b/MasterPassword/Java/masterpassword-android/res/values/strings.xml
@@ -12,7 +12,7 @@
Counter
Algorithm
- Integrity Tests
+ Integrity Tests ❯
Test suite unavailable.
Retest
Testing device\'s password generation integrity…
@@ -20,6 +20,6 @@
Incompatible device or OS.
Retest
Integrity checks passed!
- Continue
+ Close
Use native key derivation
diff --git a/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java b/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java
index fb25c644..e16627eb 100644
--- a/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java
+++ b/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java
@@ -32,6 +32,7 @@ public class EmergencyActivity extends Activity {
private static final ClipData EMPTY_CLIP = new ClipData( new ClipDescription( "", new String[0] ), new ClipData.Item( "" ) );
private static final int PASSWORD_NOTIFICATION = 0;
+ private final Preferences preferences = Preferences.get( this );
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
private final ValueChangedListener updateMasterKey = new ValueChangedListener() {
@Override
@@ -104,9 +105,9 @@ public class EmergencyActivity extends Activity {
fullNameField.setOnFocusChangeListener( updateMasterKey );
masterPasswordField.setOnFocusChangeListener( updateMasterKey );
siteNameField.addTextChangedListener( updateSitePassword );
-// siteTypeField.setOnItemSelectedListener( updateSitePassword );
+ // siteTypeField.setOnItemSelectedListener( updateSitePassword );
counterField.addTextChangedListener( updateSitePassword );
-// siteVersionField.setOnItemSelectedListener( updateMasterKey );
+ // siteVersionField.setOnItemSelectedListener( updateMasterKey );
sitePasswordField.addTextChangedListener( new ValueChangedListener() {
@Override
void update() {
@@ -127,32 +128,32 @@ public class EmergencyActivity extends Activity {
sitePasswordField.setTypeface( Res.sourceCodePro_Black );
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
-// siteTypeField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MPSiteType.forClass( MPSiteTypeClass.Generated ) ) );
-// siteTypeField.setSelection( MPSiteType.GeneratedLong.ordinal() );
+ // siteTypeField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MPSiteType.forClass( MPSiteTypeClass.Generated ) ) );
+ // siteTypeField.setSelection( MPSiteType.GeneratedLong.ordinal() );
-// siteVersionField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MasterKey.Version.values() ) );
-// siteVersionField.setSelection( MasterKey.Version.CURRENT.ordinal() );
+ // siteVersionField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MasterKey.Version.values() ) );
+ // siteVersionField.setSelection( MasterKey.Version.CURRENT.ordinal() );
rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
- getPreferences( MODE_PRIVATE ).edit().putBoolean( "rememberFullName", isChecked ).apply();
+ preferences.setRememberFullName( isChecked );
if (isChecked)
- getPreferences( MODE_PRIVATE ).edit().putString( "fullName", fullNameField.getText().toString() ).apply();
+ preferences.setFullName( fullNameField.getText().toString() );
else
- getPreferences( MODE_PRIVATE ).edit().putString( "fullName", "" ).apply();
+ preferences.setFullName( null );
}
} );
forgetPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
- getPreferences( MODE_PRIVATE ).edit().putBoolean( "forgetPassword", isChecked ).apply();
+ preferences.setForgetPassword( isChecked );
}
} );
maskPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
- getPreferences( MODE_PRIVATE ).edit().putBoolean( "maskPassword", isChecked ).apply();
+ preferences.setMaskPassword( isChecked );
sitePasswordField.setTransformationMethod( isChecked? new PasswordTransformationMethod(): null );
}
} );
@@ -162,13 +163,13 @@ public class EmergencyActivity extends Activity {
protected void onResume() {
super.onResume();
- MasterKey.setAllowNativeByDefault( isNativeKDFEnabled() );
+ MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
- fullNameField.setText( getPreferences( MODE_PRIVATE ).getString( "fullName", "" ) );
- rememberFullNameField.setChecked( isRememberFullNameEnabled() );
- forgetPasswordField.setChecked( isForgetPasswordEnabled() );
- maskPasswordField.setChecked( isMaskPasswordEnabled() );
- sitePasswordField.setTransformationMethod( isMaskPasswordEnabled()? new PasswordTransformationMethod(): null );
+ fullNameField.setText( preferences.getFullName() );
+ rememberFullNameField.setChecked( preferences.isRememberFullName() );
+ forgetPasswordField.setChecked( preferences.isForgetPassword() );
+ maskPasswordField.setChecked( preferences.isMaskPassword() );
+ sitePasswordField.setTransformationMethod( preferences.isMaskPassword()? new PasswordTransformationMethod(): null );
if (TextUtils.isEmpty( masterPasswordField.getText() ))
masterPasswordField.requestFocus();
@@ -178,7 +179,7 @@ public class EmergencyActivity extends Activity {
@Override
protected void onPause() {
- if (isForgetPasswordEnabled()) {
+ if (preferences.isForgetPassword()) {
synchronized (this) {
hc_userName = hc_masterPassword = 0;
if (masterKeyFuture != null) {
@@ -197,22 +198,6 @@ public class EmergencyActivity extends Activity {
super.onPause();
}
- private boolean isNativeKDFEnabled() {
- return getPreferences( MODE_PRIVATE ).getBoolean( "nativeKDF", MasterKey.isAllowNativeByDefault() );
- }
-
- private boolean isRememberFullNameEnabled() {
- return getPreferences( MODE_PRIVATE ).getBoolean( "rememberFullName", false );
- }
-
- private boolean isForgetPasswordEnabled() {
- return getPreferences( MODE_PRIVATE ).getBoolean( "forgetPassword", false );
- }
-
- private boolean isMaskPasswordEnabled() {
- return getPreferences( MODE_PRIVATE ).getBoolean( "maskPassword", false );
- }
-
private synchronized void updateMasterKey() {
final String fullName = fullNameField.getText().toString();
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
@@ -228,8 +213,8 @@ public class EmergencyActivity extends Activity {
hc_userName = fullName.hashCode();
hc_masterPassword = Arrays.hashCode( masterPassword );
- if (isRememberFullNameEnabled())
- getPreferences( MODE_PRIVATE ).edit().putString( "fullName", fullName ).apply();
+ if (preferences.isRememberFullName())
+ preferences.setFullName( fullName );
if (masterKeyFuture != null)
masterKeyFuture.cancel( true );
diff --git a/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/Preferences.java b/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/Preferences.java
new file mode 100644
index 00000000..9fa8d1d3
--- /dev/null
+++ b/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/Preferences.java
@@ -0,0 +1,120 @@
+package com.lyndir.masterpassword;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+
+/**
+ * @author lhunath, 2016-02-20
+ */
+public class Preferences {
+
+ private static final String PREF_TESTS_PASSED = "integrityTestsPassed";
+ private static final String PREF_NATIVE_KDF = "nativeKDF";
+ private static final String PREF_REMEMBER_FULL_NAME = "rememberFullName";
+ private static final String PREF_FORGET_PASSWORD = "forgetPassword";
+ private static final String PREF_MASK_PASSWORD = "maskPassword";
+ private static final String PREF_FULL_NAME = "fullName";
+ private static Preferences instance;
+
+ private final Context context;
+ @Nullable
+ private SharedPreferences prefs;
+
+ public static synchronized Preferences get(final Context context) {
+ if (instance == null)
+ instance = new Preferences( context );
+
+ return instance;
+ }
+
+ private Preferences(Context context) {
+ this.context = context.getApplicationContext();
+ }
+
+ @Nonnull
+ private SharedPreferences prefs() {
+ if (prefs == null)
+ prefs = context.getSharedPreferences( getClass().getCanonicalName(), Context.MODE_PRIVATE );
+
+ return prefs;
+ }
+
+ public boolean setNativeKDFEnabled(boolean enabled) {
+ if (isAllowNativeKDF() == enabled)
+ return false;
+
+ prefs().edit().putBoolean( PREF_NATIVE_KDF, enabled ).apply();
+ return true;
+ }
+
+ public boolean isAllowNativeKDF() {
+ return prefs().getBoolean( PREF_NATIVE_KDF, MasterKey.isAllowNativeByDefault() );
+ }
+
+ public boolean setTestsPassed(final Set testsPassed) {
+ if (Sets.symmetricDifference( getTestsPassed(), testsPassed ).isEmpty())
+ return false;
+
+ prefs().edit().putStringSet( PREF_TESTS_PASSED, testsPassed ).apply();
+ return true;
+ }
+
+ public Set getTestsPassed() {
+ return prefs().getStringSet( PREF_TESTS_PASSED, ImmutableSet.of() );
+ }
+
+ public boolean setRememberFullName(boolean enabled) {
+ if (isRememberFullName() == enabled)
+ return false;
+
+ prefs().edit().putBoolean( PREF_REMEMBER_FULL_NAME, enabled ).apply();
+ return true;
+ }
+
+ public boolean isRememberFullName() {
+ return prefs().getBoolean( PREF_REMEMBER_FULL_NAME, false );
+ }
+
+ public boolean setForgetPassword(boolean enabled) {
+ if (isForgetPassword() == enabled)
+ return false;
+
+ prefs().edit().putBoolean( PREF_FORGET_PASSWORD, enabled ).apply();
+ return true;
+ }
+
+ public boolean isForgetPassword() {
+ return prefs().getBoolean( PREF_FORGET_PASSWORD, false );
+ }
+
+ public boolean setMaskPassword(boolean enabled) {
+ if (isMaskPassword() == enabled)
+ return false;
+
+ prefs().edit().putBoolean( PREF_MASK_PASSWORD, enabled ).apply();
+ return true;
+ }
+
+ public boolean isMaskPassword() {
+ return prefs().getBoolean( PREF_MASK_PASSWORD, false );
+ }
+
+ public boolean setFullName(@Nullable String fullName) {
+ if (getFullName().equals( fullName ))
+ return false;
+
+ prefs().edit().putString( PREF_FULL_NAME, fullName ).apply();
+ return true;
+ }
+
+ @Nonnull
+ public String getFullName() {
+ return prefs().getString( PREF_FULL_NAME, "" );
+ }
+}
diff --git a/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/TestActivity.java b/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/TestActivity.java
index 52937610..51956eb6 100644
--- a/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/TestActivity.java
+++ b/MasterPassword/Java/masterpassword-android/src/main/java/com/lyndir/masterpassword/TestActivity.java
@@ -14,7 +14,6 @@ import com.google.common.base.*;
import com.google.common.collect.*;
import com.google.common.util.concurrent.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
-import java.util.Set;
import java.util.concurrent.*;
import javax.annotation.Nullable;
@@ -22,9 +21,9 @@ import javax.annotation.Nullable;
public class TestActivity extends Activity implements MPTestSuite.Listener {
@SuppressWarnings("UnusedDeclaration")
- private static final Logger logger = Logger.get( TestActivity.class );
- private static final String PREF_TESTS_PASSED = "integrityTestsPassed";
+ private static final Logger logger = Logger.get( TestActivity.class );
+ private final Preferences preferences = Preferences.get( this );
private final ListeningExecutorService backgroundExecutor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
private final ListeningExecutorService mainExecutor = MoreExecutors.listeningDecorator( new MainThreadExecutor() );
@@ -63,8 +62,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
nativeKDF.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
- getPreferences( MODE_PRIVATE ).edit().putBoolean( "nativeKDF", isChecked ).apply();
- MasterKey.setAllowNativeByDefault( isNativeKDFEnabled() );
+ MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
}
} );
@@ -96,21 +94,17 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
protected void onResume() {
super.onResume();
- nativeKDF.setChecked( isNativeKDFEnabled() );
+ nativeKDF.setChecked( preferences.isAllowNativeKDF() );
if (testFuture == null)
startTestSuite();
}
- private boolean isNativeKDFEnabled() {
- return getPreferences( MODE_PRIVATE ).getBoolean( "nativeKDF", MasterKey.isAllowNativeByDefault() );
- }
-
private void startTestSuite() {
if (testFuture != null)
testFuture.cancel( true );
- MasterKey.setAllowNativeByDefault( isNativeKDFEnabled() );
+ MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback() {
@@ -120,9 +114,8 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
setStatus( R.string.tests_passed, R.string.tests_btn_passed, new Runnable() {
@Override
public void run() {
- getPreferences( MODE_PRIVATE ).edit().putStringSet( PREF_TESTS_PASSED, testNames ).apply();
+ preferences.setTestsPassed( testNames );
finish();
- EmergencyActivity.start( TestActivity.this );
}
} );
else