mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-05-14 22:12:55 +00:00
Request permission to show notifications
This is needed since API 33, because we show a "Vault unlocked" notification if the user has enabled encryption and has unlocked the vault.
This commit is contained in:
parent
642864fca1
commit
1e3ceefeec
7 changed files with 53 additions and 2 deletions
|
@ -1,11 +1,13 @@
|
||||||
package com.beemdevelopment.aegis;
|
package com.beemdevelopment.aegis;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.test.espresso.UiController;
|
import androidx.test.espresso.UiController;
|
||||||
import androidx.test.espresso.ViewAction;
|
import androidx.test.espresso.ViewAction;
|
||||||
import androidx.test.platform.app.InstrumentationRegistry;
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
|
||||||
import com.beemdevelopment.aegis.crypto.CryptoUtils;
|
import com.beemdevelopment.aegis.crypto.CryptoUtils;
|
||||||
import com.beemdevelopment.aegis.crypto.SCryptParameters;
|
import com.beemdevelopment.aegis.crypto.SCryptParameters;
|
||||||
|
@ -42,6 +44,9 @@ public abstract class AegisTest {
|
||||||
@Rule
|
@Rule
|
||||||
public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
|
public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final GrantPermissionRule permRule = GrantPermissionRule.grant(Manifest.permission.POST_NOTIFICATIONS);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected VaultManager _vaultManager;
|
protected VaultManager _vaultManager;
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ public class IntroTest extends AegisTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doIntro_None() {
|
public void doIntro_None() {
|
||||||
|
assertFalse(_prefs.isIntroDone());
|
||||||
ViewInteraction next = onView(withId(R.id.btnNext));
|
ViewInteraction next = onView(withId(R.id.btnNext));
|
||||||
ViewInteraction prev = onView(withId(R.id.btnPrevious));
|
ViewInteraction prev = onView(withId(R.id.btnPrevious));
|
||||||
|
|
||||||
|
@ -98,10 +99,12 @@ public class IntroTest extends AegisTest {
|
||||||
VaultRepository vault = _vaultManager.getVault();
|
VaultRepository vault = _vaultManager.getVault();
|
||||||
assertFalse(vault.isEncryptionEnabled());
|
assertFalse(vault.isEncryptionEnabled());
|
||||||
assertNull(vault.getCredentials());
|
assertNull(vault.getCredentials());
|
||||||
|
assertTrue(_prefs.isIntroDone());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doIntro_Password() {
|
public void doIntro_Password() {
|
||||||
|
assertFalse(_prefs.isIntroDone());
|
||||||
ViewInteraction next = onView(withId(R.id.btnNext));
|
ViewInteraction next = onView(withId(R.id.btnNext));
|
||||||
ViewInteraction prev = onView(withId(R.id.btnPrevious));
|
ViewInteraction prev = onView(withId(R.id.btnPrevious));
|
||||||
|
|
||||||
|
@ -129,10 +132,12 @@ public class IntroTest extends AegisTest {
|
||||||
assertTrue(vault.isEncryptionEnabled());
|
assertTrue(vault.isEncryptionEnabled());
|
||||||
assertTrue(slots.has(PasswordSlot.class));
|
assertTrue(slots.has(PasswordSlot.class));
|
||||||
assertFalse(slots.has(BiometricSlot.class));
|
assertFalse(slots.has(BiometricSlot.class));
|
||||||
|
assertTrue(_prefs.isIntroDone());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doIntro_Import_Plain() {
|
public void doIntro_Import_Plain() {
|
||||||
|
assertFalse(_prefs.isIntroDone());
|
||||||
Uri uri = getResourceUri("aegis_plain.json");
|
Uri uri = getResourceUri("aegis_plain.json");
|
||||||
Intent resultData = new Intent();
|
Intent resultData = new Intent();
|
||||||
resultData.setData(uri);
|
resultData.setData(uri);
|
||||||
|
@ -147,10 +152,12 @@ public class IntroTest extends AegisTest {
|
||||||
VaultRepository vault = _vaultManager.getVault();
|
VaultRepository vault = _vaultManager.getVault();
|
||||||
assertFalse(vault.isEncryptionEnabled());
|
assertFalse(vault.isEncryptionEnabled());
|
||||||
assertNull(vault.getCredentials());
|
assertNull(vault.getCredentials());
|
||||||
|
assertTrue(_prefs.isIntroDone());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doIntro_Import_Encrypted() {
|
public void doIntro_Import_Encrypted() {
|
||||||
|
assertFalse(_prefs.isIntroDone());
|
||||||
Uri uri = getResourceUri("aegis_encrypted.json");
|
Uri uri = getResourceUri("aegis_encrypted.json");
|
||||||
Intent resultData = new Intent();
|
Intent resultData = new Intent();
|
||||||
resultData.setData(uri);
|
resultData.setData(uri);
|
||||||
|
@ -169,6 +176,7 @@ public class IntroTest extends AegisTest {
|
||||||
assertTrue(vault.isEncryptionEnabled());
|
assertTrue(vault.isEncryptionEnabled());
|
||||||
assertTrue(slots.has(PasswordSlot.class));
|
assertTrue(slots.has(PasswordSlot.class));
|
||||||
assertFalse(slots.has(BiometricSlot.class));
|
assertFalse(slots.has(BiometricSlot.class));
|
||||||
|
assertTrue(_prefs.isIntroDone());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Uri getResourceUri(String resourceName) {
|
private Uri getResourceUri(String resourceName) {
|
||||||
|
|
|
@ -75,6 +75,7 @@ public class OverallTest extends AegisTest {
|
||||||
VaultRepository vault = _vaultManager.getVault();
|
VaultRepository vault = _vaultManager.getVault();
|
||||||
assertTrue(vault.isEncryptionEnabled());
|
assertTrue(vault.isEncryptionEnabled());
|
||||||
assertTrue(vault.getCredentials().getSlots().has(PasswordSlot.class));
|
assertTrue(vault.getCredentials().getSlots().has(PasswordSlot.class));
|
||||||
|
assertTrue(_prefs.isIntroDone());
|
||||||
|
|
||||||
List<VaultEntry> entries = Arrays.asList(
|
List<VaultEntry> entries = Arrays.asList(
|
||||||
generateEntry(TotpInfo.class, "Frank", "Google"),
|
generateEntry(TotpInfo.class, "Frank", "Google"),
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.camera"
|
android:name="android.hardware.camera"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.beemdevelopment.aegis.ui;
|
package com.beemdevelopment.aegis.ui;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
@ -30,6 +31,7 @@ import com.beemdevelopment.aegis.crypto.MasterKey;
|
||||||
import com.beemdevelopment.aegis.helpers.BiometricsHelper;
|
import com.beemdevelopment.aegis.helpers.BiometricsHelper;
|
||||||
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
||||||
import com.beemdevelopment.aegis.helpers.MetricsHelper;
|
import com.beemdevelopment.aegis.helpers.MetricsHelper;
|
||||||
|
import com.beemdevelopment.aegis.helpers.PermissionHelper;
|
||||||
import com.beemdevelopment.aegis.helpers.UiThreadExecutor;
|
import com.beemdevelopment.aegis.helpers.UiThreadExecutor;
|
||||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||||
import com.beemdevelopment.aegis.ui.tasks.PasswordSlotDecryptTask;
|
import com.beemdevelopment.aegis.ui.tasks.PasswordSlotDecryptTask;
|
||||||
|
@ -49,6 +51,9 @@ import javax.crypto.Cipher;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
|
|
||||||
public class AuthActivity extends AegisActivity {
|
public class AuthActivity extends AegisActivity {
|
||||||
|
// Permission request codes
|
||||||
|
private static final int CODE_PERM_NOTIFICATIONS = 0;
|
||||||
|
|
||||||
private EditText _textPassword;
|
private EditText _textPassword;
|
||||||
|
|
||||||
private SlotList _slots;
|
private SlotList _slots;
|
||||||
|
@ -85,6 +90,13 @@ public class AuthActivity extends AegisActivity {
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
_inhibitBioPrompt = intent.getBooleanExtra("inhibitBioPrompt", false);
|
_inhibitBioPrompt = intent.getBooleanExtra("inhibitBioPrompt", false);
|
||||||
|
|
||||||
|
// A persistent notification is shown to let the user know that the vault is unlocked. Permission
|
||||||
|
// to do so is required since API 33, so for existing users, we have to request permission here
|
||||||
|
// in order to be able to show the notification after unlock.
|
||||||
|
if (Build.VERSION.SDK_INT >= 33) {
|
||||||
|
PermissionHelper.request(this, CODE_PERM_NOTIFICATIONS, Manifest.permission.POST_NOTIFICATIONS);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_inhibitBioPrompt = savedInstanceState.getBoolean("inhibitBioPrompt", false);
|
_inhibitBioPrompt = savedInstanceState.getBoolean("inhibitBioPrompt", false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,18 @@ import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE
|
||||||
import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_NONE;
|
import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_NONE;
|
||||||
import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_PASS;
|
import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_PASS;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.beemdevelopment.aegis.R;
|
import com.beemdevelopment.aegis.R;
|
||||||
import com.beemdevelopment.aegis.ThemeMap;
|
import com.beemdevelopment.aegis.ThemeMap;
|
||||||
|
import com.beemdevelopment.aegis.helpers.PermissionHelper;
|
||||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||||
import com.beemdevelopment.aegis.ui.intro.IntroBaseActivity;
|
import com.beemdevelopment.aegis.ui.intro.IntroBaseActivity;
|
||||||
import com.beemdevelopment.aegis.ui.intro.SlideFragment;
|
import com.beemdevelopment.aegis.ui.intro.SlideFragment;
|
||||||
|
@ -24,6 +30,9 @@ import com.beemdevelopment.aegis.vault.slots.BiometricSlot;
|
||||||
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
||||||
|
|
||||||
public class IntroActivity extends IntroBaseActivity {
|
public class IntroActivity extends IntroBaseActivity {
|
||||||
|
// Permission request codes
|
||||||
|
private static final int CODE_PERM_NOTIFICATIONS = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -40,7 +49,7 @@ public class IntroActivity extends IntroBaseActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onBeforeSlideChanged(Class<? extends SlideFragment> oldSlide, Class<? extends SlideFragment> newSlide) {
|
protected boolean onBeforeSlideChanged(Class<? extends SlideFragment> oldSlide, @NonNull Class<? extends SlideFragment> newSlide) {
|
||||||
// hide the keyboard before every slide change
|
// hide the keyboard before every slide change
|
||||||
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
||||||
imm.hideSoftInputFromWindow(findViewById(android.R.id.content).getWindowToken(), 0);
|
imm.hideSoftInputFromWindow(findViewById(android.R.id.content).getWindowToken(), 0);
|
||||||
|
@ -67,6 +76,17 @@ public class IntroActivity extends IntroBaseActivity {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onAfterSlideChanged(@Nullable Class<? extends SlideFragment> oldSlide, @NonNull Class<? extends SlideFragment> newSlide) {
|
||||||
|
// If the user has enabled encryption, we need to request permission to show notifications
|
||||||
|
// in order to be able to show the "Vault unlocked" notification.
|
||||||
|
if (newSlide == DoneSlide.class && getState().getSerializable("creds") != null) {
|
||||||
|
if (Build.VERSION.SDK_INT >= 33) {
|
||||||
|
PermissionHelper.request(this, CODE_PERM_NOTIFICATIONS, Manifest.permission.POST_NOTIFICATIONS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDonePressed() {
|
protected void onDonePressed() {
|
||||||
Bundle state = getState();
|
Bundle state = getState();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.beemdevelopment.aegis.vault;
|
package com.beemdevelopment.aegis.vault;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.backup.BackupManager;
|
import android.app.backup.BackupManager;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
|
@ -14,6 +15,7 @@ import com.beemdevelopment.aegis.Preferences;
|
||||||
import com.beemdevelopment.aegis.R;
|
import com.beemdevelopment.aegis.R;
|
||||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
||||||
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
||||||
|
import com.beemdevelopment.aegis.helpers.PermissionHelper;
|
||||||
import com.beemdevelopment.aegis.services.NotificationService;
|
import com.beemdevelopment.aegis.services.NotificationService;
|
||||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||||
|
|
||||||
|
@ -350,8 +352,10 @@ public class VaultManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startNotificationService() {
|
private void startNotificationService() {
|
||||||
|
if (PermissionHelper.granted(_context, Manifest.permission.POST_NOTIFICATIONS)) {
|
||||||
_context.startService(getNotificationServiceIntent());
|
_context.startService(getNotificationServiceIntent());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void stopNotificationService() {
|
private void stopNotificationService() {
|
||||||
_context.stopService(getNotificationServiceIntent());
|
_context.stopService(getNotificationServiceIntent());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue