diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index aa37da4d..c36a6b66 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -48,6 +48,8 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/beemdevelopment/aegis/AegisApplication.java b/app/src/main/java/com/beemdevelopment/aegis/AegisApplication.java index b9678bbd..351f9d9a 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/AegisApplication.java +++ b/app/src/main/java/com/beemdevelopment/aegis/AegisApplication.java @@ -1,6 +1,8 @@ package com.beemdevelopment.aegis; import android.app.Application; +import android.app.NotificationChannel; +import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -11,6 +13,7 @@ import android.graphics.drawable.Icon; import android.os.Build; import com.beemdevelopment.aegis.db.DatabaseManager; +import com.beemdevelopment.aegis.services.NotificationService; import com.beemdevelopment.aegis.ui.MainActivity; import java.util.ArrayList; @@ -24,6 +27,9 @@ public class AegisApplication extends Application { private Preferences _prefs; private List _lockListeners; + private static final String CODE_LOCK_STATUS_ID = "lock_status_channel"; + private static final String CODE_LOCK_DATABASE_ACTION = "lock_database"; + @Override public void onCreate() { super.onCreate(); @@ -33,11 +39,18 @@ public class AegisApplication extends Application { // listen for SCREEN_OFF events ScreenOffReceiver receiver = new ScreenOffReceiver(); - registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_SCREEN_OFF); + intentFilter.addAction(CODE_LOCK_DATABASE_ACTION); + registerReceiver(receiver, intentFilter); if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { initAppShortcuts(); } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + initNotificationChannels(); + } } public DatabaseManager getDatabaseManager() { @@ -65,6 +78,8 @@ public class AegisApplication extends Application { for (LockListener listener : _lockListeners) { listener.onLocked(); } + + stopService(new Intent(AegisApplication.this, NotificationService.class)); } @RequiresApi(api = Build.VERSION_CODES.N_MR1) @@ -88,7 +103,21 @@ public class AegisApplication extends Application { shortcutManager.setDynamicShortcuts(Collections.singletonList(shortcut)); } - private class ScreenOffReceiver extends BroadcastReceiver { + 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); + } + } + + public class ScreenOffReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (isAutoLockEnabled()) { diff --git a/app/src/main/java/com/beemdevelopment/aegis/db/DatabaseManager.java b/app/src/main/java/com/beemdevelopment/aegis/db/DatabaseManager.java index 641632b6..4eec7a21 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/db/DatabaseManager.java +++ b/app/src/main/java/com/beemdevelopment/aegis/db/DatabaseManager.java @@ -1,10 +1,12 @@ package com.beemdevelopment.aegis.db; import android.content.Context; +import android.content.Intent; import android.os.Environment; import com.beemdevelopment.aegis.BuildConfig; import com.beemdevelopment.aegis.R; +import com.beemdevelopment.aegis.services.NotificationService; import org.json.JSONObject; @@ -72,6 +74,7 @@ public class DatabaseManager { JSONObject obj = _file.getContent(creds); _db = Database.fromJson(obj); _creds = creds; + _context.startService(new Intent(_context, NotificationService.class)); } catch (DatabaseFileException | DatabaseException e) { throw new DatabaseManagerException(e); } diff --git a/app/src/main/java/com/beemdevelopment/aegis/services/NotificationService.java b/app/src/main/java/com/beemdevelopment/aegis/services/NotificationService.java new file mode 100644 index 00000000..eec3d9ec --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/services/NotificationService.java @@ -0,0 +1,61 @@ +package com.beemdevelopment.aegis.services; + +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; + +import com.beemdevelopment.aegis.AegisApplication; +import com.beemdevelopment.aegis.R; + +public class NotificationService extends Service { + public static final int DATABASE_UNLOCKED_ID = 1; + + private static final String CODE_LOCK_STATUS_ID = "lock_status_channel"; + private static final String CODE_LOCK_DATABASE_ACTION = "lock_database"; + + public NotificationService() { + + } + + @Override + public int onStartCommand(Intent intent,int flags, int startId){ + super.onStartCommand(intent, flags, startId); + + serviceMethod(); + return Service.START_STICKY; + } + + public void serviceMethod() { + Intent intentAction = new Intent(CODE_LOCK_DATABASE_ACTION); + PendingIntent lockDatabaseIntent = PendingIntent.getBroadcast(this,1,intentAction, 0); + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CODE_LOCK_STATUS_ID) + .setSmallIcon(R.drawable.ic_fingerprint_black_24dp) + .setContentTitle(getString(R.string.app_name_full)) + .setContentText(getString(R.string.vault_unlocked_state)) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setOngoing(true) + .setContentIntent(lockDatabaseIntent); + + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); + notificationManager.notify(DATABASE_UNLOCKED_ID, builder.build()); + } + + @Override + public void onDestroy() { + super.onDestroy(); + + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); + notificationManager.cancel(DATABASE_UNLOCKED_ID); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } +} diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java index 9a32092d..5a793537 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java @@ -35,6 +35,7 @@ import com.beemdevelopment.aegis.importers.AegisImporter; import com.beemdevelopment.aegis.importers.DatabaseImporter; import com.beemdevelopment.aegis.importers.DatabaseImporterEntryException; import com.beemdevelopment.aegis.importers.DatabaseImporterException; +import com.beemdevelopment.aegis.services.NotificationService; import com.beemdevelopment.aegis.ui.models.ImportEntry; import com.beemdevelopment.aegis.ui.preferences.SwitchPreference; import com.takisoft.preferencex.PreferenceFragmentCompat; @@ -253,6 +254,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat { e.printStackTrace(); } + getActivity().stopService(new Intent(getActivity(), NotificationService.class)); updateEncryptionPreferences(); } }) @@ -745,6 +747,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat { return; } + getActivity().startService(new Intent(getActivity(), NotificationService.class)); updateEncryptionPreferences(); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 38fd48f6..078973fc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ Aegis + Aegis Authenticator AegisDev Settings Import @@ -166,4 +167,7 @@ Select picture Toggle checkboxes Search + Lock status + Aegis can create a persistent notification to notify you when the vault is locked + Vault is unlocked. Tap here to lock.