2
0

Move preferences into a global preferences controller.

This commit is contained in:
Maarten Billemont 2016-02-20 20:30:08 -05:00
parent 7f8a36e32e
commit 060ec0b5cd
5 changed files with 150 additions and 52 deletions

View File

@ -108,7 +108,7 @@
android:gravity="center" android:gravity="center"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:textColor="#FFFFFF" android:textColor="#FFFFFF"
android:textSize="32sp" android:textSize="28sp"
tools:text="LuxdZozvDuma4[" tools:text="LuxdZozvDuma4["
android:onClick="copySitePassword" /> android:onClick="copySitePassword" />

View File

@ -12,7 +12,7 @@
<string name="siteCounter_hint">Counter</string> <string name="siteCounter_hint">Counter</string>
<string name="siteVersion_hint">Algorithm</string> <string name="siteVersion_hint">Algorithm</string>
<string name="empty" /> <string name="empty" />
<string name="btn_tests">Integrity Tests</string> <string name="btn_tests">Integrity Tests </string>
<string name="tests_unavailable">Test suite unavailable.</string> <string name="tests_unavailable">Test suite unavailable.</string>
<string name="tests_btn_unavailable">Retest</string> <string name="tests_btn_unavailable">Retest</string>
<string name="tests_testing">Testing device\'s password generation integrity…</string> <string name="tests_testing">Testing device\'s password generation integrity…</string>
@ -20,6 +20,6 @@
<string name="tests_failed">Incompatible device or OS.</string> <string name="tests_failed">Incompatible device or OS.</string>
<string name="tests_btn_failed">Retest</string> <string name="tests_btn_failed">Retest</string>
<string name="tests_passed">Integrity checks passed!</string> <string name="tests_passed">Integrity checks passed!</string>
<string name="tests_btn_passed">Continue</string> <string name="tests_btn_passed">Close</string>
<string name="nativeKDF">Use native key derivation</string> <string name="nativeKDF">Use native key derivation</string>
</resources> </resources>

View File

@ -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 ClipData EMPTY_CLIP = new ClipData( new ClipDescription( "", new String[0] ), new ClipData.Item( "" ) );
private static final int PASSWORD_NOTIFICATION = 0; private static final int PASSWORD_NOTIFICATION = 0;
private final Preferences preferences = Preferences.get( this );
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() ); private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
private final ValueChangedListener updateMasterKey = new ValueChangedListener() { private final ValueChangedListener updateMasterKey = new ValueChangedListener() {
@Override @Override
@ -104,9 +105,9 @@ public class EmergencyActivity extends Activity {
fullNameField.setOnFocusChangeListener( updateMasterKey ); fullNameField.setOnFocusChangeListener( updateMasterKey );
masterPasswordField.setOnFocusChangeListener( updateMasterKey ); masterPasswordField.setOnFocusChangeListener( updateMasterKey );
siteNameField.addTextChangedListener( updateSitePassword ); siteNameField.addTextChangedListener( updateSitePassword );
// siteTypeField.setOnItemSelectedListener( updateSitePassword ); // siteTypeField.setOnItemSelectedListener( updateSitePassword );
counterField.addTextChangedListener( updateSitePassword ); counterField.addTextChangedListener( updateSitePassword );
// siteVersionField.setOnItemSelectedListener( updateMasterKey ); // siteVersionField.setOnItemSelectedListener( updateMasterKey );
sitePasswordField.addTextChangedListener( new ValueChangedListener() { sitePasswordField.addTextChangedListener( new ValueChangedListener() {
@Override @Override
void update() { void update() {
@ -127,32 +128,32 @@ public class EmergencyActivity extends Activity {
sitePasswordField.setTypeface( Res.sourceCodePro_Black ); sitePasswordField.setTypeface( Res.sourceCodePro_Black );
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG ); sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
// siteTypeField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MPSiteType.forClass( MPSiteTypeClass.Generated ) ) ); // siteTypeField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MPSiteType.forClass( MPSiteTypeClass.Generated ) ) );
// siteTypeField.setSelection( MPSiteType.GeneratedLong.ordinal() ); // siteTypeField.setSelection( MPSiteType.GeneratedLong.ordinal() );
// siteVersionField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MasterKey.Version.values() ) ); // siteVersionField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MasterKey.Version.values() ) );
// siteVersionField.setSelection( MasterKey.Version.CURRENT.ordinal() ); // siteVersionField.setSelection( MasterKey.Version.CURRENT.ordinal() );
rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
getPreferences( MODE_PRIVATE ).edit().putBoolean( "rememberFullName", isChecked ).apply(); preferences.setRememberFullName( isChecked );
if (isChecked) if (isChecked)
getPreferences( MODE_PRIVATE ).edit().putString( "fullName", fullNameField.getText().toString() ).apply(); preferences.setFullName( fullNameField.getText().toString() );
else else
getPreferences( MODE_PRIVATE ).edit().putString( "fullName", "" ).apply(); preferences.setFullName( null );
} }
} ); } );
forgetPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { forgetPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { 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() { maskPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { 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 ); sitePasswordField.setTransformationMethod( isChecked? new PasswordTransformationMethod(): null );
} }
} ); } );
@ -162,13 +163,13 @@ public class EmergencyActivity extends Activity {
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
MasterKey.setAllowNativeByDefault( isNativeKDFEnabled() ); MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
fullNameField.setText( getPreferences( MODE_PRIVATE ).getString( "fullName", "" ) ); fullNameField.setText( preferences.getFullName() );
rememberFullNameField.setChecked( isRememberFullNameEnabled() ); rememberFullNameField.setChecked( preferences.isRememberFullName() );
forgetPasswordField.setChecked( isForgetPasswordEnabled() ); forgetPasswordField.setChecked( preferences.isForgetPassword() );
maskPasswordField.setChecked( isMaskPasswordEnabled() ); maskPasswordField.setChecked( preferences.isMaskPassword() );
sitePasswordField.setTransformationMethod( isMaskPasswordEnabled()? new PasswordTransformationMethod(): null ); sitePasswordField.setTransformationMethod( preferences.isMaskPassword()? new PasswordTransformationMethod(): null );
if (TextUtils.isEmpty( masterPasswordField.getText() )) if (TextUtils.isEmpty( masterPasswordField.getText() ))
masterPasswordField.requestFocus(); masterPasswordField.requestFocus();
@ -178,7 +179,7 @@ public class EmergencyActivity extends Activity {
@Override @Override
protected void onPause() { protected void onPause() {
if (isForgetPasswordEnabled()) { if (preferences.isForgetPassword()) {
synchronized (this) { synchronized (this) {
hc_userName = hc_masterPassword = 0; hc_userName = hc_masterPassword = 0;
if (masterKeyFuture != null) { if (masterKeyFuture != null) {
@ -197,22 +198,6 @@ public class EmergencyActivity extends Activity {
super.onPause(); 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() { private synchronized void updateMasterKey() {
final String fullName = fullNameField.getText().toString(); final String fullName = fullNameField.getText().toString();
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray(); final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
@ -228,8 +213,8 @@ public class EmergencyActivity extends Activity {
hc_userName = fullName.hashCode(); hc_userName = fullName.hashCode();
hc_masterPassword = Arrays.hashCode( masterPassword ); hc_masterPassword = Arrays.hashCode( masterPassword );
if (isRememberFullNameEnabled()) if (preferences.isRememberFullName())
getPreferences( MODE_PRIVATE ).edit().putString( "fullName", fullName ).apply(); preferences.setFullName( fullName );
if (masterKeyFuture != null) if (masterKeyFuture != null)
masterKeyFuture.cancel( true ); masterKeyFuture.cancel( true );

View File

@ -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<String> testsPassed) {
if (Sets.symmetricDifference( getTestsPassed(), testsPassed ).isEmpty())
return false;
prefs().edit().putStringSet( PREF_TESTS_PASSED, testsPassed ).apply();
return true;
}
public Set<String> getTestsPassed() {
return prefs().getStringSet( PREF_TESTS_PASSED, ImmutableSet.<String>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, "" );
}
}

View File

@ -14,7 +14,6 @@ import com.google.common.base.*;
import com.google.common.collect.*; import com.google.common.collect.*;
import com.google.common.util.concurrent.*; import com.google.common.util.concurrent.*;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Set;
import java.util.concurrent.*; import java.util.concurrent.*;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -23,8 +22,8 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( TestActivity.class ); private static final Logger logger = Logger.get( TestActivity.class );
private static final String PREF_TESTS_PASSED = "integrityTestsPassed";
private final Preferences preferences = Preferences.get( this );
private final ListeningExecutorService backgroundExecutor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() ); private final ListeningExecutorService backgroundExecutor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
private final ListeningExecutorService mainExecutor = MoreExecutors.listeningDecorator( new MainThreadExecutor() ); 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() { nativeKDF.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
getPreferences( MODE_PRIVATE ).edit().putBoolean( "nativeKDF", isChecked ).apply(); MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
MasterKey.setAllowNativeByDefault( isNativeKDFEnabled() );
} }
} ); } );
@ -96,21 +94,17 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
nativeKDF.setChecked( isNativeKDFEnabled() ); nativeKDF.setChecked( preferences.isAllowNativeKDF() );
if (testFuture == null) if (testFuture == null)
startTestSuite(); startTestSuite();
} }
private boolean isNativeKDFEnabled() {
return getPreferences( MODE_PRIVATE ).getBoolean( "nativeKDF", MasterKey.isAllowNativeByDefault() );
}
private void startTestSuite() { private void startTestSuite() {
if (testFuture != null) if (testFuture != null)
testFuture.cancel( true ); testFuture.cancel( true );
MasterKey.setAllowNativeByDefault( isNativeKDFEnabled() ); MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null ); setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() { Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {
@ -120,9 +114,8 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
setStatus( R.string.tests_passed, R.string.tests_btn_passed, new Runnable() { setStatus( R.string.tests_passed, R.string.tests_btn_passed, new Runnable() {
@Override @Override
public void run() { public void run() {
getPreferences( MODE_PRIVATE ).edit().putStringSet( PREF_TESTS_PASSED, testNames ).apply(); preferences.setTestsPassed( testNames );
finish(); finish();
EmergencyActivity.start( TestActivity.this );
} }
} ); } );
else else