diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2147dc33..cf09287e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -8,6 +8,7 @@
implements ItemTouchHelperAdapter {
private ArrayList _keyProfiles;
private static Listener _listener;
+ private boolean _showIssuer;
- public KeyProfileAdapter(Listener listener) {
+ public KeyProfileAdapter(Listener listener, boolean showIssuer) {
_keyProfiles = new ArrayList<>();
_listener = listener;
+ _showIssuer = showIssuer;
+ }
+
+ public void setShowIssuer(boolean showIssuer) {
+ _showIssuer = showIssuer;
}
public void addKey(KeyProfile profile) {
@@ -36,6 +42,11 @@ public class KeyProfileAdapter extends RecyclerView.Adapter im
notifyItemRemoved(position);
}
+ public void clearKeys() {
+ _keyProfiles.clear();
+ notifyDataSetChanged();
+ }
+
@Override
public void onItemDismiss(int position) {
@@ -64,14 +75,14 @@ public class KeyProfileAdapter extends RecyclerView.Adapter im
@Override
public void onViewRecycled(KeyProfileHolder holder) {
- holder.setData(null);
+ holder.setData(null, _showIssuer);
super.onViewRecycled(holder);
}
@Override
public void onBindViewHolder(final KeyProfileHolder holder, int position) {
final KeyProfile profile = _keyProfiles.get(position);
- holder.setData(profile);
+ holder.setData(profile, _showIssuer);
holder.startUpdateLoop();
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
diff --git a/app/src/main/java/me/impy/aegis/KeyProfileHolder.java b/app/src/main/java/me/impy/aegis/KeyProfileHolder.java
index 7121037b..39aac446 100644
--- a/app/src/main/java/me/impy/aegis/KeyProfileHolder.java
+++ b/app/src/main/java/me/impy/aegis/KeyProfileHolder.java
@@ -1,9 +1,7 @@
package me.impy.aegis;
import android.animation.ObjectAnimator;
-import android.content.SharedPreferences;
import android.os.Handler;
-import android.preference.PreferenceManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.animation.LinearInterpolator;
@@ -21,23 +19,21 @@ public class KeyProfileHolder extends RecyclerView.ViewHolder {
private ImageView _profileDrawable;
private KeyProfile _keyProfile;
private ProgressBar _progressBar;
- private View _itemView;
private Handler _uiHandler;
private boolean _running = false;
- KeyProfileHolder(final View itemView) {
- super(itemView);
- _itemView = itemView;
- _profileName = itemView.findViewById(R.id.profile_name);
- _profileCode = itemView.findViewById(R.id.profile_code);
- _profileIssuer = itemView.findViewById(R.id.profile_issuer);
- _profileDrawable = itemView.findViewById(R.id.ivTextDrawable);
- _progressBar = itemView.findViewById(R.id.progressBar);
+ KeyProfileHolder(final View view) {
+ super(view);
+ _profileName = view.findViewById(R.id.profile_name);
+ _profileCode = view.findViewById(R.id.profile_code);
+ _profileIssuer = view.findViewById(R.id.profile_issuer);
+ _profileDrawable = view.findViewById(R.id.ivTextDrawable);
+ _progressBar = view.findViewById(R.id.progressBar);
_uiHandler = new Handler();
}
- public void setData(KeyProfile profile) {
+ public void setData(KeyProfile profile, boolean showIssuer) {
if ((_keyProfile = profile) == null) {
_running = false;
return;
@@ -46,9 +42,7 @@ public class KeyProfileHolder extends RecyclerView.ViewHolder {
_profileName.setText(profile.getEntry().getName());
_profileCode.setText(profile.getCode());
_profileIssuer.setText("");
-
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(_itemView.getContext());
- if (sharedPreferences.getBoolean("pref_issuer", false)) {
+ if (showIssuer) {
_profileIssuer.setText(" - " + profile.getEntry().getInfo().getIssuer());
}
diff --git a/app/src/main/java/me/impy/aegis/MainActivity.java b/app/src/main/java/me/impy/aegis/MainActivity.java
index 3313eb26..79122daa 100644
--- a/app/src/main/java/me/impy/aegis/MainActivity.java
+++ b/app/src/main/java/me/impy/aegis/MainActivity.java
@@ -6,13 +6,11 @@ import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.media.MediaScannerConnection;
import android.os.Build;
-import android.preference.PreferenceManager;
import android.support.design.widget.BottomSheetDialog;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
@@ -58,6 +56,7 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter
private static final int CODE_PERM_CAMERA = 2;
private KeyProfileAdapter _keyProfileAdapter;
+ private AegisApplication _app;
private DatabaseManager _db;
private boolean _nightMode = false;
@@ -66,40 +65,18 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- _db = new DatabaseManager(getApplicationContext());
+ _app = (AegisApplication) getApplication();
+ _db = _app.getDatabaseManager();
- SharedPreferences prefs = this.getSharedPreferences("me.impy.aegis", Context.MODE_PRIVATE);
- if (!prefs.getBoolean("passedIntro", false)) {
- Intent intro = new Intent(this, IntroActivity.class);
- startActivityForResult(intro, CODE_DO_INTRO);
- } else {
- try {
- _db.load();
- if (!_db.isDecrypted()) {
- Intent intent = new Intent(this, AuthActivity.class);
- intent.putExtra("slots", _db.getFile().getSlots());
- startActivityForResult(intent, CODE_DECRYPT);
- }
- } catch (FileNotFoundException e) {
- // start the intro if the db file was not found
- Toast.makeText(this, "Database file not found, starting over...", Toast.LENGTH_SHORT).show();
- Intent intro = new Intent(this, IntroActivity.class);
- startActivityForResult(intro, CODE_DO_INTRO);
- } catch (Exception e) {
- e.printStackTrace();
- Toast.makeText(this, "An error occurred while trying to deserialize the database", Toast.LENGTH_LONG).show();
- throw new UndeclaredThrowableException(e);
- }
- }
-
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- if (sharedPreferences.getBoolean("pref_night_mode", false)) {
+ // set the theme
+ if (_app.getPreferences().getBoolean("pref_night_mode", false)) {
_nightMode = true;
setTheme(R.style.AppTheme_Dark_NoActionBar);
} else {
setPreferredTheme();
}
+ // set up the main view
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
@@ -108,25 +85,49 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter
initializeAppShortcuts();
doShortcutActions();
+ // set up the floating action button
FloatingActionButton fab = findViewById(R.id.fab);
fab.setEnabled(true);
- fab.setOnClickListener(view -> {
- onGetKeyInfo();
- });
+ fab.setOnClickListener(view -> onGetKeyInfo());
+ // set up the recycler view for the key profiles
+ _keyProfileAdapter = new KeyProfileAdapter(this, _app.getPreferences().getBoolean("pref_issuer", false));
RecyclerView rvKeyProfiles = findViewById(R.id.rvKeyProfiles);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
rvKeyProfiles.setLayoutManager(mLayoutManager);
-
- _keyProfileAdapter = new KeyProfileAdapter(this);
- if (_db.isDecrypted()) {
- loadKeyProfiles();
- }
-
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(_keyProfileAdapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(rvKeyProfiles);
rvKeyProfiles.setAdapter(_keyProfileAdapter);
+
+ if (!_app.isRunning() && !_db.isUnlocked()) {
+ if (!_app.getPreferences().getBoolean("pref_intro", false)) {
+ Intent intro = new Intent(this, IntroActivity.class);
+ startActivityForResult(intro, CODE_DO_INTRO);
+ } else {
+ try {
+ _db.load();
+ if (!_db.isUnlocked()) {
+ Intent intent = new Intent(this, AuthActivity.class);
+ intent.putExtra("slots", _db.getFile().getSlots());
+ startActivityForResult(intent, CODE_DECRYPT);
+ }
+ } catch (FileNotFoundException e) {
+ // start the intro if the db file was not found
+ Toast.makeText(this, "Database file not found, starting over...", Toast.LENGTH_SHORT).show();
+ Intent intro = new Intent(this, IntroActivity.class);
+ startActivityForResult(intro, CODE_DO_INTRO);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Toast.makeText(this, "An error occurred while trying to deserialize the database", Toast.LENGTH_LONG).show();
+ throw new UndeclaredThrowableException(e);
+ }
+ }
+ }
+
+ if (_db.isUnlocked()) {
+ loadKeyProfiles();
+ }
}
@Override
@@ -176,6 +177,8 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter
private void onPreferencesResult(int resultCode, Intent data) {
// refresh the entire key profile list if needed
if (data.getBooleanExtra("needsRefresh", false)) {
+ boolean showIssuer = _app.getPreferences().getBoolean("pref_issuer", false);
+ _keyProfileAdapter.setShowIssuer(showIssuer);
_keyProfileAdapter.notifyDataSetChanged();
}
@@ -344,8 +347,8 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter
MasterKey key = (MasterKey) data.getSerializableExtra("key");
try {
_db.load();
- if (!_db.isDecrypted()) {
- _db.setMasterKey(key);
+ if (!_db.isUnlocked()) {
+ _db.unlock(key);
}
} catch (Exception e) {
e.printStackTrace();
@@ -360,7 +363,7 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter
private void onDecryptResult(int resultCode, Intent data) {
MasterKey key = (MasterKey) data.getSerializableExtra("key");
try {
- _db.setMasterKey(key);
+ _db.unlock(key);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "An error occurred while trying to decrypt the database", Toast.LENGTH_LONG).show();
@@ -375,7 +378,7 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter
private void doShortcutActions() {
Intent intent = getIntent();
String mode = intent.getStringExtra("Action");
- if (mode == null || !_db.isDecrypted()) {
+ if (mode == null || !_db.isUnlocked()) {
return;
}
@@ -475,8 +478,16 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter
}
return true;
case R.id.action_lock:
- // TODO: properly close the database
- recreate();
+ _keyProfileAdapter.clearKeys();
+ try {
+ _db.lock();
+ } catch (Exception e) {
+ e.printStackTrace();
+ Toast.makeText(this, "An error occurred while trying to lock the database", Toast.LENGTH_LONG).show();
+ }
+ Intent intent = new Intent(this, AuthActivity.class);
+ intent.putExtra("slots", _db.getFile().getSlots());
+ startActivityForResult(intent, CODE_DECRYPT);
return true;
default:
return super.onOptionsItemSelected(item);
@@ -514,8 +525,7 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter
private void setPreferredTheme() {
boolean restart = false;
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- if (sharedPreferences.getBoolean("pref_night_mode", false)) {
+ if (_app.getPreferences().getBoolean("pref_night_mode", false)) {
if (!_nightMode) {
setTheme(R.style.AppTheme_Dark_NoActionBar);
restart = true;
@@ -555,7 +565,7 @@ public class MainActivity extends AppCompatActivity implements KeyProfileAdapter
private void updateLockIcon() {
// hide the lock icon if the database is not encrypted
- if (_menu != null && _db.isDecrypted()) {
+ if (_menu != null && _db.isUnlocked()) {
MenuItem item = _menu.findItem(R.id.action_lock);
item.setVisible(_db.getFile().isEncrypted());
}
diff --git a/app/src/main/java/me/impy/aegis/PreferencesActivity.java b/app/src/main/java/me/impy/aegis/PreferencesActivity.java
index fa7fde1e..6293e3f9 100644
--- a/app/src/main/java/me/impy/aegis/PreferencesActivity.java
+++ b/app/src/main/java/me/impy/aegis/PreferencesActivity.java
@@ -1,23 +1,23 @@
package me.impy.aegis;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
-import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
public class PreferencesActivity extends AppCompatActivity {
public static final int ACTION_EXPORT = 0;
+ private AegisApplication _app;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ _app = (AegisApplication) getApplication();
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
- if (preferences.getBoolean("pref_night_mode", false)) {
+ if (_app.getPreferences().getBoolean("pref_night_mode", false)) {
setTheme(R.style.AppTheme_Dark);
} else {
setTheme(R.style.AppTheme_Default);
diff --git a/app/src/main/java/me/impy/aegis/db/DatabaseManager.java b/app/src/main/java/me/impy/aegis/db/DatabaseManager.java
index b05c4fd6..85f7e7d0 100644
--- a/app/src/main/java/me/impy/aegis/db/DatabaseManager.java
+++ b/app/src/main/java/me/impy/aegis/db/DatabaseManager.java
@@ -57,7 +57,14 @@ public class DatabaseManager {
}
}
- public void setMasterKey(MasterKey key) throws Exception {
+ public void lock() throws Exception {
+ assertUnlocked();
+ // TODO: properly clear everything
+ _key = null;
+ _db = null;
+ }
+
+ public void unlock(MasterKey key) throws Exception {
assertLoaded();
byte[] encrypted = _file.getContent();
CryptParameters params = _file.getCryptParameters();
@@ -83,7 +90,7 @@ public class DatabaseManager {
}
public void save() throws Exception {
- assertDecrypted();
+ assertUnlocked();
byte[] dbBytes = _db.serialize();
if (!_file.isEncrypted()) {
_file.setContent(dbBytes);
@@ -96,7 +103,7 @@ public class DatabaseManager {
}
public String export(boolean encrypt) throws Exception {
- assertDecrypted();
+ assertUnlocked();
byte[] bytes = _db.serialize();
encrypt = encrypt && getFile().isEncrypted();
if (encrypt) {
@@ -129,22 +136,22 @@ public class DatabaseManager {
}
public void addKey(DatabaseEntry entry) throws Exception {
- assertDecrypted();
+ assertUnlocked();
_db.addKey(entry);
}
public void removeKey(DatabaseEntry entry) throws Exception {
- assertDecrypted();
+ assertUnlocked();
_db.removeKey(entry);
}
public void swapKeys(DatabaseEntry entry1, DatabaseEntry entry2) throws Exception {
- assertDecrypted();
+ assertUnlocked();
_db.swapKeys(entry1, entry2);
}
public List getKeys() throws Exception {
- assertDecrypted();
+ assertUnlocked();
return _db.getKeys();
}
@@ -156,7 +163,7 @@ public class DatabaseManager {
return _file != null;
}
- public boolean isDecrypted() {
+ public boolean isUnlocked() {
return _db != null;
}
@@ -166,10 +173,10 @@ public class DatabaseManager {
}
}
- private void assertDecrypted() throws Exception {
+ private void assertUnlocked() throws Exception {
assertLoaded();
- if (!isDecrypted()) {
- throw new Exception("database file has not been decrypted yet");
+ if (!isUnlocked()) {
+ throw new Exception("database file has not been unlocked yet");
}
}
}