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