2
0

Android improvements.

[UPDATED]   Opal API
[ADDED]     Scrypt native binaries for more archs.
[IMPROVED]  Android activity secure.
[FIXED]     White background on buttons for some devices.
[IMPROVED]  Android layout.
[WIP]       Remember password on Android.
This commit is contained in:
Maarten Billemont 2015-01-31 10:55:08 -05:00
parent ca5d83d40c
commit a6e7a749bf
7 changed files with 93 additions and 74 deletions

View File

@ -24,12 +24,12 @@
<dependency>
<groupId>com.lyndir.lhunath.opal</groupId>
<artifactId>opal-system</artifactId>
<version>1.6-p6</version>
<version>1.6-p7</version>
</dependency>
<dependency>
<groupId>com.lyndir.lhunath.opal</groupId>
<artifactId>opal-crypto</artifactId>
<version>1.6-p6</version>
<version>1.6-p7</version>
</dependency>
<!-- EXTERNAL DEPENDENCIES -->

View File

@ -77,15 +77,6 @@ public class MasterKey {
return idForBytes( masterKey );
}
private byte[] getSubKey(final int subkeyLength) {
Preconditions.checkState( valid );
byte[] subkey = new byte[Math.min( subkeyLength, masterKey.length )];
System.arraycopy( masterKey, 0, subkey, 0, subkey.length );
return subkey;
}
public String encode(final String siteName, final MPSiteType siteType, int siteCounter, final MPSiteVariant siteVariant,
@Nullable final String siteContext) {
Preconditions.checkState( valid );

View File

@ -114,11 +114,10 @@
<dependency>
<groupId>com.lambdaworks</groupId>
<artifactId>libscrypt</artifactId>
<version>1.4.0</version>
<type>so</type>
<classifier>android</classifier>
<scope>runtime</scope>
<artifactId>scrypt</artifactId>
<version>1.4.0-android</version>
<type>jar</type>
<classifier>native</classifier>
</dependency>
</dependencies>

View File

@ -12,64 +12,61 @@
android:gravity="center">
<View
android:layout_width="0dp"
android:layout_width="1dp"
android:layout_height="0dp"
android:layout_weight="1" />
<ProgressBar
android:id="@+id/progressView"
android:layout_width="wrap_content"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:indeterminate="true" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<EditText
android:id="@+id/userNameField"
android:layout_width="wrap_content"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:inputType="text|textCapWords|textPersonName"
android:hint="@string/userName.hint"
android:hint="@string/userName_hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="26sp" />
<EditText
android:id="@+id/masterPasswordField"
android:layout_width="wrap_content"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:inputType="text|textPassword"
android:hint="@string/masterPassword.hint"
android:password="true"
android:hint="@string/masterPassword_hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="18sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/double_"
android:contentDescription="@string/empty" />
<EditText
android:id="@+id/siteNameField"
android:layout_width="wrap_content"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:inputType="text|textNoSuggestions|textUri"
android:hint="@string/siteName.hint"
android:hint="@string/siteName_hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="26sp" />
<Button
<ImageView
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="30dp"
android:src="@drawable/double_"
android:contentDescription="@string/empty" />
<TextView
android:id="@+id/sitePasswordField"
android:layout_width="wrap_content"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@null"
android:background="@android:color/transparent"
android:textColor="#FFFFFF"
android:textSize="32sp"
android:text="LuxdZozvDuma4["
@ -77,13 +74,30 @@
<Spinner
android:id="@+id/typeField"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:layout_width="300dp"
android:layout_height="wrap_content"
android:gravity="center" />
<NumberPicker
<EditText
android:id="@+id/counterField"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:layout_width="300dp"
android:layout_height="wrap_content"
android:gravity="center"
android:inputType="text|textNoSuggestions"
android:textColor="#FFFFFF"
android:textSize="26sp"
android:text="1" />
<View
android:layout_width="1dp"
android:layout_height="0dp"
android:layout_weight="1" />
<CheckBox
android:id="@+id/rememberPasswordField"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:text="@string/remember" />
</LinearLayout>

View File

@ -2,8 +2,9 @@
<resources>
<string name="app_name">Master Password</string>
<string name="avatar">User Avatar</string>
<string name="siteName.hint">Site Name</string>
<string name="userName.hint">Your Name</string>
<string name="masterPassword.hint">Your Master Password</string>
<string name="remember">Remember Password</string>
<string name="siteName_hint">Site Name</string>
<string name="userName_hint">Your Name</string>
<string name="masterPassword_hint">Your Master Password</string>
<string name="empty" />
</resources>

View File

@ -9,12 +9,14 @@ import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.WindowManager;
import android.widget.*;
import butterknife.ButterKnife;
import butterknife.InjectView;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import java.util.concurrent.*;
@ -55,11 +57,14 @@ public class EmergencyActivity extends Activity {
Spinner typeField;
@InjectView(R.id.counterField)
NumberPicker counterField;
EditText counterField;
@InjectView(R.id.sitePasswordField)
TextView sitePasswordField;
@InjectView(R.id.rememberPasswordField)
CheckBox rememberPasswordField;
private int hc_userName;
private int hc_masterPassword;
@ -68,6 +73,7 @@ public class EmergencyActivity extends Activity {
super.onCreate( savedInstanceState );
Res.init( getResources() );
getWindow().setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE );
setContentView( R.layout.activity_emergency );
ButterKnife.inject( this );
@ -75,23 +81,26 @@ public class EmergencyActivity extends Activity {
masterPasswordField.setOnFocusChangeListener( updateMasterKey );
siteNameField.addTextChangedListener( updateSitePassword );
typeField.setOnItemSelectedListener( updateSitePassword );
counterField.setOnValueChangedListener( updateSitePassword );
counterField.addTextChangedListener( updateSitePassword );
userNameField.setTypeface( Res.exo_Thin );
userNameField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
masterPasswordField.setTypeface( Res.sourceCodePro_ExtraLight );
masterPasswordField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
masterPasswordField.setPaintFlags( masterPasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
siteNameField.setTypeface( Res.exo_Regular );
siteNameField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
siteNameField.setPaintFlags( siteNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
sitePasswordField.setTypeface( Res.sourceCodePro_Black );
sitePasswordField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
typeField.setAdapter( new ArrayAdapter<>( this, R.layout.type_item, MPSiteType.forClass( MPSiteTypeClass.Generated ) ) );
typeField.setSelection( MPSiteType.GeneratedLong.ordinal() );
counterField.setMinValue( 1 );
counterField.setMaxValue( Integer.MAX_VALUE );
counterField.setWrapSelectorWheel( false );
rememberPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
getPreferences( MODE_PRIVATE ).edit().putBoolean( "rememberPassword", isChecked ).apply();
}
} );
}
@Override
@ -99,25 +108,32 @@ public class EmergencyActivity extends Activity {
super.onResume();
userNameField.setText( getPreferences( MODE_PRIVATE ).getString( "userName", "" ) );
rememberPasswordField.setSelected( isRememberPasswordEnabled() );
masterPasswordField.requestFocus();
}
@Override
protected void onPause() {
synchronized (this) {
hc_userName = hc_masterPassword = 0;
if (masterKeyFuture != null) {
masterKeyFuture.cancel( true );
masterKeyFuture = null;
if (!isRememberPasswordEnabled()) {
synchronized (this) {
hc_userName = hc_masterPassword = 0;
if (masterKeyFuture != null) {
masterKeyFuture.cancel( true );
masterKeyFuture = null;
}
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
}
}
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
super.onPause();
}
private boolean isRememberPasswordEnabled() {
return getPreferences( MODE_PRIVATE ).getBoolean( "rememberPassword", false );
}
private synchronized void updateMasterKey() {
final String userName = userNameField.getText().toString();
final String masterPassword = masterPasswordField.getText().toString();
@ -126,9 +142,7 @@ public class EmergencyActivity extends Activity {
hc_userName = userName.hashCode();
hc_masterPassword = masterPassword.hashCode();
SharedPreferences.Editor pref = getPreferences( MODE_PRIVATE ).edit();
pref.putString( "userName", userName );
pref.apply();
getPreferences( MODE_PRIVATE ).edit().putString( "userName", userName ).apply();
if (masterKeyFuture != null)
masterKeyFuture.cancel( true );
@ -170,7 +184,7 @@ public class EmergencyActivity extends Activity {
private void updateSitePassword() {
final String siteName = siteNameField.getText().toString();
final MPSiteType type = (MPSiteType) typeField.getSelectedItem();
final int counter = counterField.getValue();
final int counter = ConversionUtils.toIntegerNN( counterField.getText() );
if (masterKeyFuture == null || siteName.isEmpty() || type == null) {
sitePasswordField.setText( "" );
@ -220,13 +234,13 @@ public class EmergencyActivity extends Activity {
ClipDescription description = new ClipDescription( strf( "Password for %s", siteNameField.getText() ),
new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } );
((ClipboardManager) getSystemService( CLIPBOARD_SERVICE )).setPrimaryClip(
new ClipData( description, new ClipData.Item( sitePassword ) ) );
ClipData clipData = new ClipData( description, new ClipData.Item( sitePassword ) );
((ClipboardManager) getSystemService( CLIPBOARD_SERVICE )).setPrimaryClip( clipData );
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
Intent startMain = new Intent( Intent.ACTION_MAIN );
startMain.addCategory( Intent.CATEGORY_HOME );
startMain.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
startActivity( startMain );
}
private abstract class ValueChangedListener

View File

@ -7,7 +7,7 @@
<parent>
<groupId>com.lyndir.lhunath</groupId>
<artifactId>lyndir</artifactId>
<version>1.18</version>
<version>1.20</version>
</parent>
<name>Master Password</name>