Skip to content

Commit

Permalink
Merge branch 'release-2.5.6'
Browse files Browse the repository at this point in the history
* release-2.5.6:
  Update version code and name for release 2.5.6
  Translations: Squashed commit of the following:
  strings: add a proper set of duration names for future use
  CONTRIBUTING: translations PRs should be done to the translation branch
  circle.yml: disable coverage report for now
  Make PIN timeout actually work
  Make app lock timeout configurable
  PinLockActivity: make fingerprint work with the new pin verification model
  Privacy prefs: require PIN confirmation before PIN delete/modify
  StartActivity: close app if PIN input is canceled
  PinLockActivity: make the back button undo input if possible
  PinLockActivity: make PIN verification a result call as well
  Display that AEMPS database is from Spain.
  Update kotlin version to 1.2.50
  Update gradle plugin to 3.1.3
  • Loading branch information
AlvaroBrey committed Jul 18, 2018
2 parents 770d046 + c276ff9 commit 3803d6b
Show file tree
Hide file tree
Showing 27 changed files with 938 additions and 132 deletions.
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ Non-code contributions are also welcome!. You can do a lot of things:

> Join the BETA channel: [click here!](https://play.google.com/apps/testing/es.usc.citius.servando.calendula)

### Help with app translations

Contributing translations is now easier than ever! Just join us at POEditor using [this link](https://poeditor.com/join/project/kIdyqFodDn) and start translating Calendula to one of the existing languages, or suggest a new one. **This is the recommended method for translations**.
You can also contribute with better translations for particular words or sentences.

Alternatively, you can contribute translations via pull request:

* Add a new folder named `values-{LANG}/` at `Calendula/src/main/res/`
* Translate the `strings_translatable.xml` file from `values` to your desired language.
* Send a pull request.
* Add a new folder named `values-{LANG}/` at `Calendula/src/main/res/`.
* Translate the `strings_translatable.xml` file from `Calendula/src/main/res/values` to your desired language.
* Send a pull request to the `translations` branch.

You can also improve an existing `strings_translatable.xml` file and make a PR with that!
4 changes: 2 additions & 2 deletions Calendula/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 25
versionCode 36
versionName "2.5.5"
versionCode 37
versionName "2.5.6"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
applicationId "es.usc.citius.servando.calendula"
multiDexEnabled true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
Expand All @@ -38,6 +39,11 @@
import java.util.HashMap;
import java.util.Map;

import es.usc.citius.servando.calendula.activities.StartActivity;
import es.usc.citius.servando.calendula.pinlock.PINManager;
import es.usc.citius.servando.calendula.pinlock.PinLockActivity;
import es.usc.citius.servando.calendula.pinlock.UnlockStateManager;
import es.usc.citius.servando.calendula.util.LogUtil;
import es.usc.citius.servando.calendula.util.PermissionUtils;
import es.usc.citius.servando.calendula.util.ScreenUtils;

Expand Down Expand Up @@ -177,4 +183,16 @@ public void onClick(DialogInterface dialog, int id) {
alert.show();
}

@Override
protected void onResume() {
super.onResume();
if (PINManager.isPINSet() && !UnlockStateManager.getInstance().isUnlocked() && !(this instanceof PinLockActivity)) {
// If we get unlock timeout on resume, we'll call StartActivity to ask for a PIN
LogUtil.d("CalendulaActivity", "Unlock has expired");
final Intent i = new Intent(this, StartActivity.class);
i.putExtra(StartActivity.EXTRA_RETURN_TO_PREVIOUS, true);
//i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Calendula - An assistant for personal medication management.
* Copyright (C) 2014-2018 CiTIUS - University of Santiago de Compostela
*
* Calendula 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.
*
* This program 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 should have received a copy of the GNU General Public License
* along with this software. If not, see <http://www.gnu.org/licenses/>.
*/

package es.usc.citius.servando.calendula.activities


import android.app.Activity
import android.content.Intent
import android.os.Bundle

import es.usc.citius.servando.calendula.HomePagerActivity
import es.usc.citius.servando.calendula.pinlock.PINManager
import es.usc.citius.servando.calendula.pinlock.PinLockActivity
import es.usc.citius.servando.calendula.pinlock.UnlockStateManager


class StartActivity : Activity() {

companion object {
const val EXTRA_RETURN_TO_PREVIOUS = "StartActivity.extras.return_to_previous"
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
verifyUnlockAndLaunch()
}

private fun verifyUnlockAndLaunch() {
if (PINManager.isPINSet() && !UnlockStateManager.getInstance().isUnlocked) {
val i = Intent(this, PinLockActivity::class.java)
i.action = PinLockActivity.ACTION_VERIFY_PIN
startActivityForResult(i, PinLockActivity.REQUEST_VERIFY)
} else {
val returnToPrevious = intent.getBooleanExtra(EXTRA_RETURN_TO_PREVIOUS,false)
if (!returnToPrevious) {
// if "return to previous" is specified, just finish this activity to go back in the stack
startActivity(Intent(this, HomePagerActivity::class.java))
}
finish()
}
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PinLockActivity.REQUEST_VERIFY) {
if (resultCode == Activity.RESULT_CANCELED) {
finish()
} else {
verifyUnlockAndLaunch()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,12 @@

public class PinLockActivity extends CalendulaActivity {

public static final String EXTRA_PIN = "PinLockActivity.result";
public static final String EXTRA_NEW_PIN = "PinLockActivity.newpin.result";
public static final String EXTRA_VERIFY_PIN_RESULT = "PinLockActivity.verify.result";
public static final String ACTION_NEW_PIN = "PinLockActivity.action.new_pin";
public static final String ACTION_VERIFY_PIN = "PinLockActivity.action.verify_pin";
public static final int REQUEST_PIN = 15765;
public static final int REQUEST_VERIFY = 15766;
private static final int PIN_SIZE = 4;

private static final String TAG = "PinLockActivity";
Expand Down Expand Up @@ -125,6 +129,7 @@ void launchFingerprintAuth() {
fpHelper.startAuthentication(new LoginFPCallbackAdapter(this, fingerprintDialog));
}

@RequiresApi(Build.VERSION_CODES.M)
private void showFingerprintDialog() {
fingerprintDialog = new MaterialDialog.Builder(this)
.icon(IconUtils.icon(this, CommunityMaterial.Icon.cmd_fingerprint, R.color.android_blue_dark, 48))
Expand All @@ -148,6 +153,15 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_pin_lock);
ButterKnife.bind(this);

if (!isCalledForResult()) {
throw new IllegalStateException("This activity can only be called for result");
}

final String action = getIntent().getAction();
if (action == null) {
throw new IllegalArgumentException("Action required!");
}

pinInputStateManager = new PinInputStateManager(PIN_SIZE);
indicatorDotView.setSize(PIN_SIZE);

Expand Down Expand Up @@ -176,23 +190,25 @@ public void onPinChange(String currentPin, int pinLength) {
android.graphics.PorterDuff.Mode.MULTIPLY);

setupStatusBar(ContextCompat.getColor(this, R.color.android_blue_dark));
if (isCalledForResult()) {
// if called for result we will return a PIN
pinInputStateManager.setPinCompleteListener(new NewPinListener());
promptMessage.setText(R.string.text_pinlock_new_prompt);
setupToolbar(null, ContextCompat.getColor(this, R.color.android_blue_dark));
} else {
// if not called for result, we will authorize access
pinInputStateManager.setPinCompleteListener(new AuthorizeAccessListener());
errorMessage.setVisibility(View.GONE); // indicator shows error
promptMessage.setText(R.string.text_pinlock_auth_prompt);
footer.setVisibility(View.VISIBLE);
toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.toolbar);
toolbar.setVisibility(View.GONE);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setupFingerprintAuth();
}

switch (action) {
case ACTION_NEW_PIN:
pinInputStateManager.setPinCompleteListener(new NewPinListener());
promptMessage.setText(R.string.text_pinlock_new_prompt);
setupToolbar(null, ContextCompat.getColor(this, R.color.android_blue_dark));
break;
case ACTION_VERIFY_PIN:
pinInputStateManager.setPinCompleteListener(new AuthorizeAccessListener());
errorMessage.setVisibility(View.GONE); // indicator shows error
promptMessage.setText(R.string.text_pinlock_auth_prompt);
footer.setVisibility(View.VISIBLE);
toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.toolbar);
toolbar.setVisibility(View.GONE);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setupFingerprintAuth();
}
break;
}
}

Expand Down Expand Up @@ -233,6 +249,14 @@ private boolean isCalledForResult() {
return calledForResult;
}

@Override
public void onBackPressed() {
// delete a number if possible, else go back
if (!pinInputStateManager.delete()) {
super.onBackPressed();
}
}

private class NewPinListener implements PinInputStateManager.PinInputCompleteListener {

private String firstPin;
Expand All @@ -256,7 +280,7 @@ public void run() {
if (pin.equals(firstPin)) {
// everything's fine, return the PIN
Intent returnIntent = new Intent();
returnIntent.putExtra(EXTRA_PIN, pin);
returnIntent.putExtra(EXTRA_NEW_PIN, pin);
setResult(Activity.RESULT_OK, returnIntent);
LogUtil.d(TAG, "PIN input correct");
finish();
Expand Down Expand Up @@ -291,11 +315,8 @@ public void onComplete(String pin) {
boolean checkPIN = PINManager.checkPIN(pin);
if (checkPIN) {
//PIN is correct, forward to main activity
LogUtil.d(TAG, "PIN is correct, setting unlock and forwarding to main activity");
UnlockStateManager.getInstance().unlock();
Intent i = new Intent(PinLockActivity.this, StartActivity.class);
startActivity(i);
finish();
LogUtil.d(TAG, "PIN is correct");
returnVerifiedResult();
} else {
new Handler().postDelayed(new Runnable() {
@Override
Expand All @@ -314,13 +335,21 @@ public void run() {

}

private void returnVerifiedResult() {
Intent returnIntent = new Intent();
returnIntent.putExtra(EXTRA_VERIFY_PIN_RESULT, true);
setResult(Activity.RESULT_OK, returnIntent);
UnlockStateManager.getInstance().unlock();
finish();
}


private static class LoginFPCallbackAdapter implements FingerprintHelper.FingerprintCallbackAdapter {

private Activity activity;
private PinLockActivity activity;
private MaterialDialog fingerprintDialog;

LoginFPCallbackAdapter(Activity activity, MaterialDialog fingerprintDialog) {
LoginFPCallbackAdapter(PinLockActivity activity, MaterialDialog fingerprintDialog) {
this.activity = activity;
this.fingerprintDialog = fingerprintDialog;
}
Expand All @@ -344,10 +373,15 @@ public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult re
fingerprintDialog.setContent(R.string.fingerprint_unlock_dialog_successful_message);
fingerprintDialog.setIcon(IconUtils.icon(activity, GoogleMaterial.Icon.gmd_check_circle, R.color.android_green, 48));
}
UnlockStateManager.getInstance().unlock();
Intent i = new Intent(activity, StartActivity.class);
activity.startActivity(i);
activity.finish();

switch (activity.getIntent().getAction()) {
case ACTION_NEW_PIN:
throw new IllegalArgumentException("No fingerprint allowed for new pin recording");
case ACTION_VERIFY_PIN:
activity.returnVerifiedResult();
break;
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@
import org.joda.time.Duration;

import es.usc.citius.servando.calendula.util.LogUtil;
import es.usc.citius.servando.calendula.util.PreferenceKeys;
import es.usc.citius.servando.calendula.util.PreferenceUtils;

/**
* Utility class to handle unlock state (for PIN lock)
*/
public class UnlockStateManager {

private final static Duration MAX_UNLOCK_DURATION = Duration.standardMinutes(5);
private final static String DEFAULT_UNLOCK_DURATION_SECONDS = "120";
private final static String TAG = "UnlockStateManager";
private static UnlockStateManager theInstance;
private DateTime unlockTimestamp;
Expand Down Expand Up @@ -76,7 +78,11 @@ public boolean isUnlocked() {
LogUtil.v(TAG, "isUnlocked() called");
if (unlockTimestamp != null) {
Duration diff = new Duration(unlockTimestamp, DateTime.now());
if (diff.compareTo(MAX_UNLOCK_DURATION) <= 0) {
// need to be a string to use a ListPreference
final String maxDurationStr = PreferenceUtils.getString(PreferenceKeys.UNLOCK_PIN_TIMEOUT, DEFAULT_UNLOCK_DURATION_SECONDS);
Duration maxDuration = Duration.standardSeconds(Integer.parseInt(maxDurationStr));
LogUtil.d(TAG, "Max unlock duration is " + maxDuration.toString());
if (diff.compareTo(maxDuration) <= 0) {
LogUtil.d(TAG, "isUnlocked() returned: " + true);
return true;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ interface PrivacyPrefsContract {
interface View : IView {

fun recordPIN()
fun verifyPIN(requestCode: Int)
fun showPINOptions()
fun showConfirmDeletePinChoice()
fun setPINPrefText(@StringRes pinPrefText: Int)
fun setFingerprintPrefEnabled(enabled: Boolean)
fun setPINDependentPrefsEnabled(enabled: Boolean)
fun showEnableFingerprintDialog()

}

interface Presenter : IPresenter<View> {
Expand Down
Loading

0 comments on commit 3803d6b

Please sign in to comment.