Require authentication again after screen off

Closes #36
This commit is contained in:
Jakob Nixdorf 2017-08-25 15:44:44 +02:00
parent ad0c2f46b8
commit 842d49b68f
No known key found for this signature in database
GPG key ID: BE99BF86574A7DBC
4 changed files with 132 additions and 48 deletions

View file

@ -42,7 +42,7 @@ import org.shadowice.flocke.andotp.R;
import static org.shadowice.flocke.andotp.Utilities.Settings.AuthMethod;
public class AuthenticateActivity extends BaseActivity
public class AuthenticateActivity extends ThemedActivity
implements EditText.OnEditorActionListener {
private String password;

View file

@ -22,64 +22,55 @@
package org.shadowice.flocke.andotp.Activities;
import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import org.shadowice.flocke.andotp.R;
import org.shadowice.flocke.andotp.Utilities.Settings;
import static org.shadowice.flocke.andotp.Utilities.Settings.AuthMethod;
public class BaseActivity extends AppCompatActivity {
private static final int INTENT_INTERNAL_AUTHENTICATE = 1;
public Settings settings;
public abstract class BaseActivity extends ThemedActivity {
private ScreenOffReceiver screenOffReceiver;
private BroadcastReceivedCallback broadcastReceivedCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
settings = new Settings(this);
String theme = settings.getTheme();
if (theme.equals("light")) {
setTheme(R.style.AppTheme_NoActionBar);
} else if (theme.equals("dark")) {
setTheme(R.style.AppTheme_Dark_NoActionBar);
}
super.onCreate(savedInstanceState);
}
public void authenticate() {
AuthMethod authMethod = settings.getAuthMethod();
if (authMethod == AuthMethod.DEVICE) {
KeyguardManager km = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP && km.isKeyguardSecure()) {
Intent authIntent = km.createConfirmDeviceCredentialIntent(getString(R.string.dialog_title_auth), getString(R.string.dialog_msg_auth));
startActivityForResult(authIntent, INTENT_INTERNAL_AUTHENTICATE);
}
} else if (authMethod == AuthMethod.PASSWORD || authMethod == AuthMethod.PIN) {
Intent authIntent = new Intent(this, AuthenticateActivity.class);
startActivityForResult(authIntent, INTENT_INTERNAL_AUTHENTICATE);
}
screenOffReceiver = new ScreenOffReceiver();
registerReceiver(screenOffReceiver, screenOffReceiver.filter);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
protected void onDestroy() {
unregisterReceiver(screenOffReceiver);
if (requestCode == INTENT_INTERNAL_AUTHENTICATE && resultCode != RESULT_OK) {
Toast.makeText(getBaseContext(), R.string.toast_auth_failed, Toast.LENGTH_LONG).show();
super.onDestroy();
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
finishAndRemoveTask();
} else {
finish();
private void destroyIfNotMain() {
if (getClass() != MainActivity.class)
finish();
}
public void setBroadcastCallback(BroadcastReceivedCallback cb) {
this.broadcastReceivedCallback = cb;
}
public class ScreenOffReceiver extends BroadcastReceiver {
public IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
if (broadcastReceivedCallback != null)
broadcastReceivedCallback.onReceivedScreenOff();
destroyIfNotMain();
}
}
}
interface BroadcastReceivedCallback {
void onReceivedScreenOff();
}
}

View file

@ -25,6 +25,7 @@ package org.shadowice.flocke.andotp.Activities;
import android.animation.ObjectAnimator;
import android.app.AlertDialog;
import android.app.KeyguardManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
@ -52,6 +53,7 @@ import android.widget.Toast;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import org.shadowice.flocke.andotp.Utilities.Settings;
import org.shadowice.flocke.andotp.View.EntriesCardAdapter;
import org.shadowice.flocke.andotp.Database.Entry;
import org.shadowice.flocke.andotp.View.FloatingActionMenu;
@ -65,8 +67,9 @@ import static org.shadowice.flocke.andotp.Utilities.Settings.SortMode;
public class MainActivity extends BaseActivity
implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final int INTENT_INTERNAL_SETTINGS = 101;
private static final int INTENT_INTERNAL_BACKUP = 102;
private static final int INTENT_INTERNAL_AUTHENTICATE = 100;
private static final int INTENT_INTERNAL_SETTINGS = 101;
private static final int INTENT_INTERNAL_BACKUP = 102;
private EntriesCardAdapter adapter;
private FloatingActionMenu floatingActionMenu;
@ -74,6 +77,8 @@ public class MainActivity extends BaseActivity
private MenuItem sortMenu;
private SimpleItemTouchHelperCallback touchHelperCallback;
private boolean requireAuthentication = false;
private Handler handler;
private Runnable handlerTask;
@ -149,6 +154,21 @@ public class MainActivity extends BaseActivity
.show();
}
public void authenticate() {
Settings.AuthMethod authMethod = settings.getAuthMethod();
if (authMethod == Settings.AuthMethod.DEVICE) {
KeyguardManager km = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP && km.isKeyguardSecure()) {
Intent authIntent = km.createConfirmDeviceCredentialIntent(getString(R.string.dialog_title_auth), getString(R.string.dialog_msg_auth));
startActivityForResult(authIntent, INTENT_INTERNAL_AUTHENTICATE);
}
} else if (authMethod == Settings.AuthMethod.PASSWORD || authMethod == Settings.AuthMethod.PIN) {
Intent authIntent = new Intent(this, AuthenticateActivity.class);
startActivityForResult(authIntent, INTENT_INTERNAL_AUTHENTICATE);
}
}
private void restoreSortMode() {
if (settings != null && adapter != null && touchHelperCallback != null) {
SortMode mode = settings.getSortMode();
@ -182,7 +202,14 @@ public class MainActivity extends BaseActivity
settings.registerPreferenceChangeListener(this);
if (savedInstanceState == null)
authenticate();
requireAuthentication = true;
setBroadcastCallback(new BroadcastReceivedCallback() {
@Override
public void onReceivedScreenOff() {
requireAuthentication = true;
}
});
if (! settings.getFirstTimeWarningShown()) {
showFirstTimeWarning();
@ -279,6 +306,12 @@ public class MainActivity extends BaseActivity
@Override
public void onResume() {
super.onResume();
if (requireAuthentication) {
requireAuthentication = false;
authenticate();
}
startUpdater();
}
@ -317,6 +350,18 @@ public class MainActivity extends BaseActivity
} else if (requestCode == INTENT_INTERNAL_BACKUP && resultCode == RESULT_OK) {
if (intent.getBooleanExtra("reload", false))
adapter.loadEntries();
} else if (requestCode == INTENT_INTERNAL_AUTHENTICATE) {
if (resultCode != RESULT_OK) {
Toast.makeText(getBaseContext(), R.string.toast_auth_failed, Toast.LENGTH_LONG).show();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
finishAndRemoveTask();
} else {
finish();
}
} else {
requireAuthentication = false;
}
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2017 Jakob Nixdorf
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.shadowice.flocke.andotp.Activities;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import org.shadowice.flocke.andotp.R;
import org.shadowice.flocke.andotp.Utilities.Settings;
public abstract class ThemedActivity extends AppCompatActivity {
public Settings settings;
@Override
protected void onCreate(Bundle savedInstanceState) {
settings = new Settings(this);
String theme = settings.getTheme();
if (theme.equals("light")) {
setTheme(R.style.AppTheme_NoActionBar);
} else if (theme.equals("dark")) {
setTheme(R.style.AppTheme_Dark_NoActionBar);
}
super.onCreate(savedInstanceState);
}
}