2019-02-07 22:39:33 +01:00
|
|
|
package com.beemdevelopment.aegis;
|
2017-12-23 22:33:32 +01:00
|
|
|
|
|
|
|
import android.app.Application;
|
2019-06-12 01:49:26 +02:00
|
|
|
import android.app.NotificationChannel;
|
|
|
|
import android.app.NotificationManager;
|
2019-04-07 18:18:50 +02:00
|
|
|
import android.content.BroadcastReceiver;
|
|
|
|
import android.content.Context;
|
2017-12-26 13:04:26 +01:00
|
|
|
import android.content.Intent;
|
2019-04-07 18:18:50 +02:00
|
|
|
import android.content.IntentFilter;
|
2017-12-26 13:04:26 +01:00
|
|
|
import android.content.pm.ShortcutInfo;
|
|
|
|
import android.content.pm.ShortcutManager;
|
|
|
|
import android.graphics.drawable.Icon;
|
|
|
|
import android.os.Build;
|
2019-02-07 22:39:33 +01:00
|
|
|
|
2020-08-12 21:33:25 +02:00
|
|
|
import androidx.annotation.NonNull;
|
2019-12-25 19:21:34 +01:00
|
|
|
import androidx.annotation.RequiresApi;
|
2020-08-12 21:33:25 +02:00
|
|
|
import androidx.lifecycle.Lifecycle;
|
|
|
|
import androidx.lifecycle.LifecycleEventObserver;
|
|
|
|
import androidx.lifecycle.LifecycleOwner;
|
|
|
|
import androidx.lifecycle.ProcessLifecycleOwner;
|
2019-12-25 19:21:34 +01:00
|
|
|
|
2020-07-08 11:18:40 +02:00
|
|
|
import com.beemdevelopment.aegis.icons.IconPackManager;
|
2019-06-12 01:49:26 +02:00
|
|
|
import com.beemdevelopment.aegis.services.NotificationService;
|
2019-02-07 22:39:33 +01:00
|
|
|
import com.beemdevelopment.aegis.ui.MainActivity;
|
2020-10-25 21:42:26 +01:00
|
|
|
import com.beemdevelopment.aegis.util.IOUtils;
|
2020-05-02 18:51:12 +02:00
|
|
|
import com.beemdevelopment.aegis.vault.Vault;
|
|
|
|
import com.beemdevelopment.aegis.vault.VaultFile;
|
|
|
|
import com.beemdevelopment.aegis.vault.VaultFileCredentials;
|
2019-12-25 19:21:34 +01:00
|
|
|
import com.beemdevelopment.aegis.vault.VaultManager;
|
2020-05-02 18:51:12 +02:00
|
|
|
import com.beemdevelopment.aegis.vault.VaultManagerException;
|
2019-09-14 15:20:02 +02:00
|
|
|
import com.mikepenz.iconics.Iconics;
|
|
|
|
import com.mikepenz.material_design_iconic_typeface_library.MaterialDesignIconic;
|
2020-12-20 13:53:34 +01:00
|
|
|
import com.topjohnwu.superuser.Shell;
|
2019-02-07 22:39:33 +01:00
|
|
|
|
2019-05-12 17:12:09 +02:00
|
|
|
import java.util.ArrayList;
|
2017-12-26 13:04:26 +01:00
|
|
|
import java.util.Collections;
|
2019-05-12 17:12:09 +02:00
|
|
|
import java.util.List;
|
2017-12-23 22:33:32 +01:00
|
|
|
|
|
|
|
public class AegisApplication extends Application {
|
2020-05-02 18:51:12 +02:00
|
|
|
private VaultFile _vaultFile;
|
2019-12-25 19:21:34 +01:00
|
|
|
private VaultManager _manager;
|
2018-05-11 21:29:10 +02:00
|
|
|
private Preferences _prefs;
|
2019-05-12 17:12:09 +02:00
|
|
|
private List<LockListener> _lockListeners;
|
2020-12-23 11:38:57 +01:00
|
|
|
private boolean _blockAutoLock;
|
2020-07-08 11:18:40 +02:00
|
|
|
private IconPackManager _iconPackManager;
|
2017-12-23 22:33:32 +01:00
|
|
|
|
2019-06-12 01:49:26 +02:00
|
|
|
private static final String CODE_LOCK_STATUS_ID = "lock_status_channel";
|
2019-12-25 19:21:34 +01:00
|
|
|
private static final String CODE_LOCK_VAULT_ACTION = "lock_vault";
|
2019-06-12 01:49:26 +02:00
|
|
|
|
2020-12-20 13:53:34 +01:00
|
|
|
static {
|
|
|
|
// to access other app's internal storage directory, run libsu commands inside the global mount namespace
|
2021-05-08 10:10:08 +02:00
|
|
|
Shell.setDefaultBuilder(Shell.Builder.create().setFlags(Shell.FLAG_MOUNT_MASTER));
|
2020-12-20 13:53:34 +01:00
|
|
|
}
|
|
|
|
|
2017-12-23 22:33:32 +01:00
|
|
|
@Override
|
|
|
|
public void onCreate() {
|
|
|
|
super.onCreate();
|
2018-05-11 21:29:10 +02:00
|
|
|
_prefs = new Preferences(this);
|
2019-05-12 17:12:09 +02:00
|
|
|
_lockListeners = new ArrayList<>();
|
2020-07-08 11:18:40 +02:00
|
|
|
_iconPackManager = new IconPackManager(this);
|
2017-12-26 13:04:26 +01:00
|
|
|
|
2019-09-14 15:20:02 +02:00
|
|
|
Iconics.init(this);
|
|
|
|
Iconics.registerFont(new MaterialDesignIconic());
|
|
|
|
|
2019-04-07 18:18:50 +02:00
|
|
|
// listen for SCREEN_OFF events
|
|
|
|
ScreenOffReceiver receiver = new ScreenOffReceiver();
|
2019-06-12 01:49:26 +02:00
|
|
|
IntentFilter intentFilter = new IntentFilter();
|
|
|
|
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
2019-12-25 19:21:34 +01:00
|
|
|
intentFilter.addAction(CODE_LOCK_VAULT_ACTION);
|
2019-06-12 01:49:26 +02:00
|
|
|
registerReceiver(receiver, intentFilter);
|
2019-04-07 18:18:50 +02:00
|
|
|
|
2020-08-12 21:33:25 +02:00
|
|
|
// lock the app if the user moves the application to the background
|
|
|
|
ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppLifecycleObserver());
|
|
|
|
|
2020-10-25 21:42:26 +01:00
|
|
|
// clear the cache directory on startup, to make sure no temporary vault export files remain
|
|
|
|
IOUtils.clearDirectory(getCacheDir(), false);
|
|
|
|
|
2017-12-26 13:04:26 +01:00
|
|
|
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
|
|
|
initAppShortcuts();
|
|
|
|
}
|
2019-06-12 01:49:26 +02:00
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
|
initNotificationChannels();
|
|
|
|
}
|
2017-12-23 22:33:32 +01:00
|
|
|
}
|
|
|
|
|
2020-05-02 18:51:12 +02:00
|
|
|
public boolean isVaultLocked() {
|
|
|
|
return _manager == null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads the vault file from disk at the default location, stores an internal
|
|
|
|
* reference to it for future use and returns it. This must only be called before
|
|
|
|
* initVaultManager() or after lock().
|
|
|
|
*/
|
|
|
|
public VaultFile loadVaultFile() throws VaultManagerException {
|
|
|
|
if (!isVaultLocked()) {
|
|
|
|
throw new AssertionError("loadVaultFile() may only be called before initVaultManager() or after lock()");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_vaultFile == null) {
|
2021-01-03 18:19:16 +01:00
|
|
|
_vaultFile = VaultManager.readVaultFile(this);
|
2020-05-02 18:51:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return _vaultFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the vault manager by decrypting the given vaultFile with the given
|
|
|
|
* creds. This removes the internal reference to the raw vault file.
|
|
|
|
*/
|
|
|
|
public VaultManager initVaultManager(VaultFile vaultFile, VaultFileCredentials creds) throws VaultManagerException {
|
|
|
|
_vaultFile = null;
|
|
|
|
_manager = VaultManager.init(this, vaultFile, creds);
|
|
|
|
return _manager;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the vault manager with the given vault and creds. This removes the
|
|
|
|
* internal reference to the raw vault file.
|
|
|
|
*/
|
|
|
|
public VaultManager initVaultManager(Vault vault, VaultFileCredentials creds) {
|
|
|
|
_vaultFile = null;
|
|
|
|
_manager = new VaultManager(this, vault, creds);
|
|
|
|
return _manager;
|
|
|
|
}
|
|
|
|
|
2019-12-25 19:21:34 +01:00
|
|
|
public VaultManager getVaultManager() {
|
2017-12-23 22:33:32 +01:00
|
|
|
return _manager;
|
|
|
|
}
|
|
|
|
|
2020-07-08 11:18:40 +02:00
|
|
|
public IconPackManager getIconPackManager() {
|
|
|
|
return _iconPackManager;
|
|
|
|
}
|
|
|
|
|
2018-05-11 20:08:51 +02:00
|
|
|
public Preferences getPreferences() {
|
|
|
|
return _prefs;
|
2017-12-23 22:33:32 +01:00
|
|
|
}
|
|
|
|
|
2020-08-12 21:33:25 +02:00
|
|
|
public boolean isAutoLockEnabled(int autoLockType) {
|
|
|
|
return _prefs.isAutoLockTypeEnabled(autoLockType) && !isVaultLocked() && _manager.isEncryptionEnabled();
|
2019-05-12 17:12:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void registerLockListener(LockListener listener) {
|
|
|
|
_lockListeners.add(listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void unregisterLockListener(LockListener listener) {
|
|
|
|
_lockListeners.remove(listener);
|
|
|
|
}
|
|
|
|
|
2020-12-23 11:38:57 +01:00
|
|
|
/**
|
|
|
|
* Sets whether to block automatic lock on minimization. This should only be called
|
|
|
|
* by activities before invoking an intent that shows a DocumentsUI, because that
|
|
|
|
* action leads AppLifecycleObserver to believe that the app has been minimized.
|
|
|
|
*/
|
|
|
|
public void setBlockAutoLock(boolean block) {
|
|
|
|
_blockAutoLock = block;
|
|
|
|
}
|
|
|
|
|
2020-08-12 21:33:25 +02:00
|
|
|
/**
|
|
|
|
* Locks the vault and the app.
|
|
|
|
* @param userInitiated whether or not the user initiated the lock in MainActivity.
|
|
|
|
*/
|
|
|
|
public void lock(boolean userInitiated) {
|
2020-11-20 16:28:08 +01:00
|
|
|
_manager.destroy();
|
2020-05-02 18:51:12 +02:00
|
|
|
_manager = null;
|
2020-11-20 16:28:08 +01:00
|
|
|
|
2019-05-12 17:12:09 +02:00
|
|
|
for (LockListener listener : _lockListeners) {
|
2020-08-12 21:33:25 +02:00
|
|
|
listener.onLocked(userInitiated);
|
2019-05-12 17:12:09 +02:00
|
|
|
}
|
2019-06-12 01:49:26 +02:00
|
|
|
|
|
|
|
stopService(new Intent(AegisApplication.this, NotificationService.class));
|
2019-05-12 17:12:09 +02:00
|
|
|
}
|
|
|
|
|
2017-12-26 13:04:26 +01:00
|
|
|
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
|
|
|
|
private void initAppShortcuts() {
|
|
|
|
ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
|
|
|
|
if (shortcutManager == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Intent intent = new Intent(this, MainActivity.class);
|
|
|
|
intent.putExtra("action", "scan");
|
2020-06-19 17:14:06 +02:00
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
2017-12-26 13:04:26 +01:00
|
|
|
intent.setAction(Intent.ACTION_MAIN);
|
|
|
|
|
|
|
|
ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "shortcut_new")
|
2020-04-11 14:37:28 +02:00
|
|
|
.setShortLabel(getString(R.string.new_entry))
|
|
|
|
.setLongLabel(getString(R.string.add_new_entry))
|
2019-05-29 23:36:52 +02:00
|
|
|
.setIcon(Icon.createWithResource(this, R.drawable.ic_qr_code))
|
2017-12-26 13:04:26 +01:00
|
|
|
.setIntent(intent)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
shortcutManager.setDynamicShortcuts(Collections.singletonList(shortcut));
|
|
|
|
}
|
2019-04-07 18:18:50 +02:00
|
|
|
|
2019-06-12 01:49:26 +02:00
|
|
|
private void initNotificationChannels() {
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
|
CharSequence name = getString(R.string.channel_name_lock_status);
|
|
|
|
String description = getString(R.string.channel_description_lock_status);
|
|
|
|
int importance = NotificationManager.IMPORTANCE_LOW;
|
|
|
|
|
|
|
|
NotificationChannel channel = new NotificationChannel(CODE_LOCK_STATUS_ID, name, importance);
|
|
|
|
channel.setDescription(description);
|
|
|
|
|
|
|
|
NotificationManager notificationManager = getSystemService(NotificationManager.class);
|
|
|
|
notificationManager.createNotificationChannel(channel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-12 21:33:25 +02:00
|
|
|
private class AppLifecycleObserver implements LifecycleEventObserver {
|
|
|
|
@Override
|
|
|
|
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
|
2020-12-23 11:38:57 +01:00
|
|
|
if (event == Lifecycle.Event.ON_STOP
|
|
|
|
&& isAutoLockEnabled(Preferences.AUTO_LOCK_ON_MINIMIZE)
|
|
|
|
&& !_blockAutoLock) {
|
2020-08-12 21:33:25 +02:00
|
|
|
lock(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class ScreenOffReceiver extends BroadcastReceiver {
|
2019-04-07 18:18:50 +02:00
|
|
|
@Override
|
|
|
|
public void onReceive(Context context, Intent intent) {
|
2020-08-12 21:33:25 +02:00
|
|
|
if (isAutoLockEnabled(Preferences.AUTO_LOCK_ON_DEVICE_LOCK)) {
|
|
|
|
lock(false);
|
2019-04-07 18:18:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-12 17:12:09 +02:00
|
|
|
|
|
|
|
public interface LockListener {
|
2020-08-12 21:33:25 +02:00
|
|
|
/**
|
|
|
|
* When called, the app/vault has been locked and the listener should perform its cleanup operations.
|
|
|
|
* @param userInitiated whether or not the user initiated the lock in MainActivity.
|
|
|
|
*/
|
|
|
|
void onLocked(boolean userInitiated);
|
2019-05-12 17:12:09 +02:00
|
|
|
}
|
2017-12-23 22:33:32 +01:00
|
|
|
}
|