From 842d49b68f86412d246c9ab9a8d59dcbc11c4f8c Mon Sep 17 00:00:00 2001 From: Jakob Nixdorf Date: Fri, 25 Aug 2017 15:44:44 +0200 Subject: [PATCH] Require authentication again after screen off Closes #36 --- .../Activities/AuthenticateActivity.java | 2 +- .../andotp/Activities/BaseActivity.java | 79 ++++++++----------- .../andotp/Activities/MainActivity.java | 51 +++++++++++- .../andotp/Activities/ThemedActivity.java | 48 +++++++++++ 4 files changed, 132 insertions(+), 48 deletions(-) create mode 100644 app/src/main/java/org/shadowice/flocke/andotp/Activities/ThemedActivity.java diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Activities/AuthenticateActivity.java b/app/src/main/java/org/shadowice/flocke/andotp/Activities/AuthenticateActivity.java index 81ff6b63..b25347c3 100644 --- a/app/src/main/java/org/shadowice/flocke/andotp/Activities/AuthenticateActivity.java +++ b/app/src/main/java/org/shadowice/flocke/andotp/Activities/AuthenticateActivity.java @@ -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; diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Activities/BaseActivity.java b/app/src/main/java/org/shadowice/flocke/andotp/Activities/BaseActivity.java index 25759958..77b1c7ee 100644 --- a/app/src/main/java/org/shadowice/flocke/andotp/Activities/BaseActivity.java +++ b/app/src/main/java/org/shadowice/flocke/andotp/Activities/BaseActivity.java @@ -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(); + } } diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Activities/MainActivity.java b/app/src/main/java/org/shadowice/flocke/andotp/Activities/MainActivity.java index 5ad13792..572878b6 100644 --- a/app/src/main/java/org/shadowice/flocke/andotp/Activities/MainActivity.java +++ b/app/src/main/java/org/shadowice/flocke/andotp/Activities/MainActivity.java @@ -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; + } } } diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Activities/ThemedActivity.java b/app/src/main/java/org/shadowice/flocke/andotp/Activities/ThemedActivity.java new file mode 100644 index 00000000..d2f98a93 --- /dev/null +++ b/app/src/main/java/org/shadowice/flocke/andotp/Activities/ThemedActivity.java @@ -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); + } +}