2
0

JDK 8 support for Android platform.

This commit is contained in:
Maarten Billemont
2018-06-10 15:22:37 -04:00
parent 4909479b0f
commit 9a564ff35e
19 changed files with 67 additions and 299 deletions

View File

@@ -2,7 +2,7 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '25.0.3'
buildToolsVersion '27.0.3'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
@@ -15,7 +15,6 @@ android {
targetSdkVersion 25
versionCode 20501
versionName '2.5.1'
jackOptions.enabled true
}
// release with: STORE_PW=$(mpw masterpassword.keystore) KEY_PW_ANDROID=$(mpw masterpassword-android) gradle masterpassword-android:assembleRelease
@@ -37,10 +36,10 @@ android {
}
dependencies {
compile project( ':masterpassword-algorithm' )
compile project( ':masterpassword-tests' )
api project( ':masterpassword-algorithm' )
implementation group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.7-p2'
compile group: 'org.slf4j', name: 'slf4j-android', version: '1.7.13-underscore'
compile group: 'com.jakewharton', name: 'butterknife', version: '8.5.1'
implementation group: 'org.slf4j', name: 'slf4j-android', version: '1.7.13-underscore'
implementation group: 'com.jakewharton', name: 'butterknife', version: '8.5.1'
annotationProcessor group: 'com.jakewharton', name: 'butterknife-compiler', version: '8.5.1'
}

View File

@@ -38,7 +38,6 @@ import com.google.common.primitives.UnsignedInteger;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.masterpassword.model.MPConstant;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.Executors;
@@ -51,7 +50,7 @@ public class EmergencyActivity extends Activity {
private static final Logger logger = Logger.get( EmergencyActivity.class );
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 CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
private static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstants.MS_PER_S;
private final Preferences preferences = Preferences.get( this );
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(
@@ -321,23 +320,15 @@ public class EmergencyActivity extends Activity {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
}
catch (final RuntimeException e) {
catch (final MPAlgorithmException e) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
logger.err( e, "While generating site password." );
throw e;
}
}
} );
}
public void integrityTests(final View view) {
if (masterKey != null)
masterKey = null;
TestActivity.startNoSkip( this );
}
public void copySitePassword(final View view) {
final String currentSitePassword = sitePassword;
if (TextUtils.isEmpty( currentSitePassword ))

View File

@@ -0,0 +1,27 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password 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.
//
// Master Password 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 can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword;
/**
* @author lhunath, 2018-06-10
*/
public class MPConstants {
public static final int MS_PER_S = 1000;
}

View File

@@ -1,168 +0,0 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password 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.
//
// Master Password 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 can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.*;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.google.common.util.concurrent.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@SuppressWarnings("PublicMethodNotExposedInInterface" /* IDEA-191044 */)
public class TestActivity extends Activity implements MPTestSuite.Listener {
@SuppressWarnings("UnusedDeclaration")
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() );
@BindView(R.id.progressView)
ProgressBar progressView;
@BindView(R.id.statusView)
TextView statusView;
@BindView(R.id.logView)
TextView logView;
@BindView(R.id.actionButton)
Button actionButton;
@BindView(R.id.nativeKDFField)
CheckBox nativeKDFField;
private MPTestSuite testSuite;
private ListenableFuture<Boolean> testFuture;
@Nullable
private Runnable action;
private Set<String> testNames;
public static void startNoSkip(final Context context) {
context.startActivity( new Intent( context, TestActivity.class ) );
}
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_test );
ButterKnife.bind( this );
nativeKDFField.setOnCheckedChangeListener( (buttonView, isChecked) -> {
preferences.setNativeKDFEnabled( isChecked );
// TODO: MasterKey.setAllowNativeByDefault( isChecked );
} );
try {
setStatus( 0, 0, null );
testSuite = new MPTestSuite();
testSuite.setListener( this );
testNames = testSuite.getTests().getCases().stream()
.map( input -> (input == null)? null: input.identifier )
.filter( Objects::nonNull ).collect( Collectors.toSet() );
}
catch (final MPTestSuite.UnavailableException e) {
logger.err( e, "While loading test suite" );
setStatus( R.string.tests_unavailable, R.string.tests_btn_unavailable, this::finish );
}
}
@Override
protected void onResume() {
super.onResume();
nativeKDFField.setChecked( preferences.isAllowNativeKDF() );
if (testFuture == null)
startTestSuite();
}
private void startTestSuite() {
if (testFuture != null)
testFuture.cancel( true );
// TODO: MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {
@Override
public void onSuccess(@Nullable final Boolean result) {
if ((result != null) && result)
setStatus( R.string.tests_passed, R.string.tests_btn_passed, () -> {
preferences.setTestsPassed( testNames );
finish();
} );
else
setStatus( R.string.tests_failed, R.string.tests_btn_failed, () -> startTestSuite() );
}
@Override
public void onFailure(final Throwable t) {
logger.err( t, "While running test suite" );
setStatus( R.string.tests_failed, R.string.tests_btn_failed, () -> finish() );
}
}, mainExecutor );
}
public void onAction(final View v) {
if (action != null)
action.run();
}
private void setStatus(final int statusId, final int buttonId, @Nullable final Runnable action) {
this.action = action;
if (statusId == 0)
statusView.setText( null );
else
statusView.setText( statusId );
if (buttonId == 0)
actionButton.setText( null );
else
actionButton.setText( buttonId );
actionButton.setEnabled( action != null );
}
@Override
public void progress(final int current, final int max, final String messageFormat, final Object... args) {
runOnUiThread( () -> {
logView.append( strf( "%n" + messageFormat, args ) );
progressView.setMax( max );
progressView.setProgress( current );
} );
}
}

View File

@@ -253,15 +253,6 @@
</LinearLayout>
</LinearLayout>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textSize="16sp"
android:text="@string/btn_tests"
android:onClick="integrityTests"
android:background="@android:color/transparent" />
<View
android:layout_width="1dp"
android:layout_height="0dp"

View File

@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:orientation="vertical"
android:gravity="center">
<View
android:layout_width="1dp"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:src="@drawable/img_stats" />
<ProgressBar
android:id="@+id/progressView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
tools:max="100"
tools:progress="80"
style="?android:progressBarStyleHorizontal" />
<TextView
android:id="@+id/statusView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:labelFor="@id/sitePasswordField"
android:gravity="center"
android:background="@android:color/transparent"
android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/tests_testing" />
<TextView
android:id="@+id/logView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="20dp"
android:gravity="bottom"
android:background="@android:color/transparent"
android:textIsSelectable="true"
android:textSize="9sp"
android:textColor="@android:color/tertiary_text_dark" />
<Button
android:id="@+id/actionButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:enabled="false"
android:text="@string/tests_btn_testing"
android:onClick="onAction" />
<CheckBox
android:id="@+id/nativeKDFField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/nativeKDF" />
</LinearLayout>
</ScrollView>