diff --git a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java
index bb58799b6..63c24088e 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java
@@ -159,7 +159,8 @@ class AccountManagerImpl implements AccountManager {
@Override
public boolean createAccount(String name, String password) {
synchronized (stateChangeLock) {
- // TODO don't allow creating another account if one already exists
+ if (hasDatabaseKey())
+ throw new AssertionError("Already have a database key");
LocalAuthor localAuthor = identityManager.createLocalAuthor(name);
identityManager.registerLocalAuthor(localAuthor);
SecretKey key = crypto.generateSecretKey();
@@ -182,6 +183,7 @@ class AccountManagerImpl implements AccountManager {
LOG.info("Deleting account");
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
+ databaseKey = null;
}
}
diff --git a/briar-android/build.gradle b/briar-android/build.gradle
index 1bb45a77c..ba6c06b31 100644
--- a/briar-android/build.gradle
+++ b/briar-android/build.gradle
@@ -2,65 +2,6 @@ apply plugin: 'com.android.application'
apply plugin: 'witness'
apply from: 'witness.gradle'
-dependencies {
- implementation project(path: ':briar-core', configuration: 'default')
- implementation project(path: ':bramble-core', configuration: 'default')
- implementation project(':bramble-android')
-
- def supportVersion = '27.1.1'
- implementation "com.android.support:support-v4:$supportVersion"
- implementation("com.android.support:appcompat-v7:$supportVersion") {
- exclude module: 'support-v4'
- }
- implementation("com.android.support:preference-v14:$supportVersion") {
- exclude module: 'support-v4'
- }
- implementation("com.android.support:design:$supportVersion") {
- exclude module: 'support-v4'
- exclude module: 'recyclerview-v7'
- }
- implementation "com.android.support:cardview-v7:$supportVersion"
- implementation "com.android.support:support-annotations:$supportVersion"
- implementation 'com.android.support.constraint:constraint-layout:1.1.3'
-
- implementation('ch.acra:acra:4.9.1') {
- exclude module: 'support-v4'
- exclude module: 'support-annotations'
- }
- implementation 'info.guardianproject.panic:panic:0.5'
- implementation 'info.guardianproject.trustedintents:trustedintents:0.2'
- implementation 'de.hdodenhof:circleimageview:2.2.0'
- implementation 'com.google.zxing:core:3.3.0'
- implementation 'uk.co.samuelwall:material-tap-target-prompt:2.8.0'
- implementation 'com.vanniktech:emoji-google:0.5.1'
-
- annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
-
- compileOnly 'javax.annotation:jsr250-api:1.0'
-
- testImplementation project(path: ':bramble-api', configuration: 'testOutput')
- testImplementation project(path: ':bramble-core', configuration: 'testOutput')
- testImplementation 'org.robolectric:robolectric:3.8'
- testImplementation 'org.robolectric:shadows-support-v4:3.3.2'
- testImplementation 'org.mockito:mockito-core:2.13.0'
- testImplementation 'junit:junit:4.12'
- testImplementation "org.jmock:jmock:2.8.2"
- testImplementation "org.jmock:jmock-junit4:2.8.2"
- testImplementation "org.jmock:jmock-legacy:2.8.2"
- testImplementation "org.hamcrest:hamcrest-library:1.3"
- testImplementation "org.hamcrest:hamcrest-core:1.3"
-
- def espressoVersion = '3.0.2'
- androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
- androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion"
- androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion"
- androidTestImplementation "tools.fastlane:screengrab:1.1.0"
- androidTestImplementation "com.android.support.test.uiautomator:uiautomator-v18:2.1.3"
- androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.0.2"
- androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
- androidTestImplementation 'junit:junit:4.12'
-}
-
def getStdout = { command, defaultValue ->
def stdout = new ByteArrayOutputStream()
try {
@@ -89,7 +30,7 @@ android {
def now = (long) (System.currentTimeMillis() / 1000)
buildConfigField "Long", "BuildTimestamp",
"${getStdout(['git', 'log', '-n', '1', '--format=%ct'], now)}000L"
- testInstrumentationRunner 'org.briarproject.briar.android.test.BriarTestRunner'
+ testInstrumentationRunner 'org.briarproject.briar.android.BriarTestRunner'
}
buildTypes {
@@ -144,6 +85,65 @@ android {
}
}
+dependencies {
+ implementation project(path: ':briar-core', configuration: 'default')
+ implementation project(path: ':bramble-core', configuration: 'default')
+ implementation project(':bramble-android')
+
+ def supportVersion = '27.1.1'
+ implementation "com.android.support:support-v4:$supportVersion"
+ implementation("com.android.support:appcompat-v7:$supportVersion") {
+ exclude module: 'support-v4'
+ }
+ implementation("com.android.support:preference-v14:$supportVersion") {
+ exclude module: 'support-v4'
+ }
+ implementation("com.android.support:design:$supportVersion") {
+ exclude module: 'support-v4'
+ exclude module: 'recyclerview-v7'
+ }
+ implementation "com.android.support:cardview-v7:$supportVersion"
+ implementation "com.android.support:support-annotations:$supportVersion"
+ implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+
+ implementation('ch.acra:acra:4.9.1') {
+ exclude module: 'support-v4'
+ exclude module: 'support-annotations'
+ }
+ implementation 'info.guardianproject.panic:panic:0.5'
+ implementation 'info.guardianproject.trustedintents:trustedintents:0.2'
+ implementation 'de.hdodenhof:circleimageview:2.2.0'
+ implementation 'com.google.zxing:core:3.3.0'
+ implementation 'uk.co.samuelwall:material-tap-target-prompt:2.8.0'
+ implementation 'com.vanniktech:emoji-google:0.5.1'
+
+ annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
+
+ compileOnly 'javax.annotation:jsr250-api:1.0'
+
+ testImplementation project(path: ':bramble-api', configuration: 'testOutput')
+ testImplementation project(path: ':bramble-core', configuration: 'testOutput')
+ testImplementation 'org.robolectric:robolectric:3.8'
+ testImplementation 'org.robolectric:shadows-support-v4:3.3.2'
+ testImplementation 'org.mockito:mockito-core:2.13.0'
+ testImplementation 'junit:junit:4.12'
+ testImplementation "org.jmock:jmock:2.8.2"
+ testImplementation "org.jmock:jmock-junit4:2.8.2"
+ testImplementation "org.jmock:jmock-legacy:2.8.2"
+ testImplementation "org.hamcrest:hamcrest-library:1.3"
+ testImplementation "org.hamcrest:hamcrest-core:1.3"
+
+ def espressoVersion = '3.0.2'
+ androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
+ androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion"
+ androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion"
+ androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.0.2"
+ androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
+ androidTestImplementation 'junit:junit:4.12'
+ androidTestScreenshotImplementation "tools.fastlane:screengrab:1.2.0"
+ androidTestScreenshotImplementation "com.android.support.test.uiautomator:uiautomator-v18:2.1.3"
+}
+
task verifyTranslations {
doLast {
def file = project.file("src/main/res/values/arrays.xml")
diff --git a/briar-android/fastlane/Screengrabfile b/briar-android/fastlane/Screengrabfile
index bacf6905b..53f4226de 100644
--- a/briar-android/fastlane/Screengrabfile
+++ b/briar-android/fastlane/Screengrabfile
@@ -1,9 +1,7 @@
app_package_name "org.briarproject.briar.android.screenshot.debug"
locales ['en-US']
-use_tests_in_classes([
- 'org.briarproject.briar.android.login.SetupActivityScreenshotTest',
- 'org.briarproject.briar.android.settings.SettingsActivityScreenshotTest',
-])
app_apk_path "build/outputs/apk/screenshot/debug/briar-android-screenshot-debug.apk"
tests_apk_path "build/outputs/apk/androidTest/screenshot/debug/briar-android-screenshot-debug-androidTest.apk"
-test_instrumentation_runner "org.briarproject.briar.android.test.BriarTestRunner"
\ No newline at end of file
+test_instrumentation_runner "org.briarproject.briar.android.BriarTestRunner"
+reinstall_app = true
+exit_on_test_failure = true
\ No newline at end of file
diff --git a/briar-android/fastlane/demo-mode-activate.sh b/briar-android/fastlane/demo-mode-activate.sh
index 23001fb56..41dbe273e 100755
--- a/briar-android/fastlane/demo-mode-activate.sh
+++ b/briar-android/fastlane/demo-mode-activate.sh
@@ -4,4 +4,8 @@ adb shell am broadcast -a com.android.systemui.demo -e command enter
adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false
adb shell am broadcast -a com.android.systemui.demo -e command battery -e level 100
adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show
-adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1337
\ No newline at end of file
+adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1337
+
+# workaround for Android Pie hidden API Espresso bug
+adb shell settings put global hidden_api_policy_pre_p_apps 1
+adb shell settings put global hidden_api_policy_p_apps 1
diff --git a/briar-android/proguard-test.txt b/briar-android/proguard-test.txt
index df4eb272e..91b89ae58 100644
--- a/briar-android/proguard-test.txt
+++ b/briar-android/proguard-test.txt
@@ -12,4 +12,4 @@
-keep class junit.** { *; }
-dontwarn junit.**
--dontwarn org.briarproject.briar.android.BriarTestComponentApplication
\ No newline at end of file
+-dontwarn org.briarproject.briar.android.**
diff --git a/briar-android/src/androidTest/java/org/briarproject/briar/android/test/BriarTestRunner.java b/briar-android/src/androidTest/java/org/briarproject/briar/android/BriarTestRunner.java
similarity index 63%
rename from briar-android/src/androidTest/java/org/briarproject/briar/android/test/BriarTestRunner.java
rename to briar-android/src/androidTest/java/org/briarproject/briar/android/BriarTestRunner.java
index bf520102d..4d1081b42 100644
--- a/briar-android/src/androidTest/java/org/briarproject/briar/android/test/BriarTestRunner.java
+++ b/briar-android/src/androidTest/java/org/briarproject/briar/android/BriarTestRunner.java
@@ -1,11 +1,9 @@
-package org.briarproject.briar.android.test;
+package org.briarproject.briar.android;
import android.app.Application;
import android.content.Context;
import android.support.test.runner.AndroidJUnitRunner;
-import org.briarproject.briar.android.BriarTestComponentApplication;
-
public class BriarTestRunner extends AndroidJUnitRunner {
@Override
@@ -13,8 +11,8 @@ public class BriarTestRunner extends AndroidJUnitRunner {
Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
- return super.newApplication(cl, BriarTestComponentApplication.class.getName(),
- context);
+ return super.newApplication(cl,
+ BriarTestComponentApplication.class.getName(), context);
}
}
diff --git a/briar-android/src/androidTest/java/org/briarproject/briar/android/UiTest.java b/briar-android/src/androidTest/java/org/briarproject/briar/android/UiTest.java
new file mode 100644
index 000000000..7d9249cfb
--- /dev/null
+++ b/briar-android/src/androidTest/java/org/briarproject/briar/android/UiTest.java
@@ -0,0 +1,79 @@
+package org.briarproject.briar.android;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.support.test.espresso.intent.rule.IntentsTestRule;
+
+import org.briarproject.bramble.api.account.AccountManager;
+import org.briarproject.bramble.api.lifecycle.LifecycleManager;
+import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.briar.R;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+
+import static android.support.test.InstrumentationRegistry.getTargetContext;
+
+@SuppressWarnings("WeakerAccess")
+public abstract class UiTest {
+
+ protected final String USERNAME =
+ getTargetContext().getString(R.string.screenshot_alice);
+ protected static final String PASSWORD = "123456";
+
+ @Inject
+ protected AccountManager accountManager;
+ @Inject
+ protected LifecycleManager lifecycleManager;
+
+ public UiTest() {
+ BriarTestComponentApplication app =
+ (BriarTestComponentApplication) getTargetContext()
+ .getApplicationContext();
+ inject((BriarUiTestComponent) app.getApplicationComponent());
+ }
+
+ protected abstract void inject(BriarUiTestComponent component);
+
+ @NotNullByDefault
+ protected class CleanAccountTestRule
+ extends IntentsTestRule {
+
+ @Nullable
+ private final Runnable runnable;
+
+ public CleanAccountTestRule(Class activityClass) {
+ super(activityClass);
+ this.runnable = null;
+ }
+
+ /**
+ * Use this if you need to run code before launching the activity.
+ * Note: You need to use {@link #launchActivity(Intent)} yourself
+ * to start the activity.
+ */
+ public CleanAccountTestRule(Class activityClass, Runnable runnable) {
+ super(activityClass, false, false);
+ this.runnable = runnable;
+ }
+
+ @Override
+ protected void beforeActivityLaunched() {
+ super.beforeActivityLaunched();
+ accountManager.deleteAccount();
+ accountManager.createAccount(USERNAME, PASSWORD);
+ if (runnable != null) {
+ Intent serviceIntent =
+ new Intent(getTargetContext(), BriarService.class);
+ getTargetContext().startService(serviceIntent);
+ try {
+ lifecycleManager.waitForStartup();
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+ runnable.run();
+ }
+ }
+ }
+
+}
diff --git a/briar-android/src/androidTest/java/org/briarproject/briar/android/test/ViewActions.java b/briar-android/src/androidTest/java/org/briarproject/briar/android/ViewActions.java
similarity index 98%
rename from briar-android/src/androidTest/java/org/briarproject/briar/android/test/ViewActions.java
rename to briar-android/src/androidTest/java/org/briarproject/briar/android/ViewActions.java
index 0d1aceba5..ac3edab65 100644
--- a/briar-android/src/androidTest/java/org/briarproject/briar/android/test/ViewActions.java
+++ b/briar-android/src/androidTest/java/org/briarproject/briar/android/ViewActions.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.test;
+package org.briarproject.briar.android;
import android.app.Activity;
import android.support.test.espresso.PerformException;
diff --git a/briar-android/src/androidTest/java/org/briarproject/briar/android/test/ScreenshotTest.java b/briar-android/src/androidTest/java/org/briarproject/briar/android/test/ScreenshotTest.java
deleted file mode 100644
index 355dd7763..000000000
--- a/briar-android/src/androidTest/java/org/briarproject/briar/android/test/ScreenshotTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.briarproject.briar.android.test;
-
-import android.app.Activity;
-import android.support.test.espresso.intent.rule.IntentsTestRule;
-import android.util.Log;
-
-import org.briarproject.bramble.api.account.AccountManager;
-import org.briarproject.bramble.api.lifecycle.LifecycleManager;
-import org.briarproject.briar.android.BriarTestComponentApplication;
-import org.briarproject.briar.android.BriarUiTestComponent;
-import org.junit.ClassRule;
-
-import javax.inject.Inject;
-
-import tools.fastlane.screengrab.Screengrab;
-import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy;
-import tools.fastlane.screengrab.locale.LocaleTestRule;
-
-import static android.support.test.InstrumentationRegistry.getTargetContext;
-import static tools.fastlane.screengrab.Screengrab.setDefaultScreenshotStrategy;
-
-public abstract class ScreenshotTest {
-
- @ClassRule
- public static final LocaleTestRule localeTestRule = new LocaleTestRule();
-
- protected static final String USERNAME = "Alice";
- protected static final String PASSWORD = "123456";
-
- @Inject
- protected AccountManager accountManager;
- @Inject
- protected LifecycleManager lifecycleManager;
-
- public ScreenshotTest() {
- super();
- setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy());
- BriarTestComponentApplication app =
- (BriarTestComponentApplication) getTargetContext()
- .getApplicationContext();
- inject((BriarUiTestComponent) app.getApplicationComponent());
- }
-
- protected abstract void inject(BriarUiTestComponent component);
-
- protected void screenshot(String name) {
- try {
- Screengrab.screenshot(name);
- } catch (RuntimeException e) {
- if (!e.getMessage().equals("Unable to capture screenshot."))
- throw e;
- // The tests should still pass when run from AndroidStudio
- // without manually granting permissions like fastlane does.
- Log.w("Screengrab", "Permission to write screenshot is missing.");
- }
- }
-
- protected class CleanAccountTestRule
- extends IntentsTestRule {
-
- public CleanAccountTestRule(Class activityClass) {
- super(activityClass);
- }
-
- @Override
- protected void beforeActivityLaunched() {
- super.beforeActivityLaunched();
- accountManager.deleteAccount();
- accountManager.createAccount(USERNAME, PASSWORD);
- }
- }
-
-}
diff --git a/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/BriarUiTestComponent.java b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/BriarUiTestComponent.java
new file mode 100644
index 000000000..8aa02d42a
--- /dev/null
+++ b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/BriarUiTestComponent.java
@@ -0,0 +1,25 @@
+package org.briarproject.briar.android;
+
+import org.briarproject.bramble.BrambleAndroidModule;
+import org.briarproject.bramble.BrambleCoreModule;
+import org.briarproject.bramble.account.BriarAccountModule;
+import org.briarproject.briar.BriarCoreModule;
+import org.briarproject.briar.android.navdrawer.NavDrawerActivityTest;
+
+import javax.inject.Singleton;
+
+import dagger.Component;
+
+@Singleton
+@Component(modules = {
+ AppModule.class,
+ BriarCoreModule.class,
+ BrambleAndroidModule.class,
+ BriarAccountModule.class,
+ BrambleCoreModule.class
+})
+public interface BriarUiTestComponent extends AndroidComponent {
+
+ void inject(NavDrawerActivityTest test);
+
+}
diff --git a/briar-android/src/androidTest/java/org/briarproject/briar/android/navdrawer/NavDrawerActivityTest.java b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/navdrawer/NavDrawerActivityTest.java
similarity index 93%
rename from briar-android/src/androidTest/java/org/briarproject/briar/android/navdrawer/NavDrawerActivityTest.java
rename to briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/navdrawer/NavDrawerActivityTest.java
index e92ae6693..5d55f2600 100644
--- a/briar-android/src/androidTest/java/org/briarproject/briar/android/navdrawer/NavDrawerActivityTest.java
+++ b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/navdrawer/NavDrawerActivityTest.java
@@ -6,8 +6,8 @@ import android.view.Gravity;
import org.briarproject.briar.R;
import org.briarproject.briar.android.BriarUiTestComponent;
+import org.briarproject.briar.android.UiTest;
import org.briarproject.briar.android.settings.SettingsActivity;
-import org.briarproject.briar.android.test.ScreenshotTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -23,7 +23,7 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
@RunWith(AndroidJUnit4.class)
-public class NavDrawerActivityTest extends ScreenshotTest {
+public class NavDrawerActivityTest extends UiTest {
@Rule
public CleanAccountTestRule testRule =
diff --git a/briar-android/src/androidTest/java/org/briarproject/briar/android/BriarUiTestComponent.java b/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/BriarUiTestComponent.java
similarity index 74%
rename from briar-android/src/androidTest/java/org/briarproject/briar/android/BriarUiTestComponent.java
rename to briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/BriarUiTestComponent.java
index f00200ac5..860166099 100644
--- a/briar-android/src/androidTest/java/org/briarproject/briar/android/BriarUiTestComponent.java
+++ b/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/BriarUiTestComponent.java
@@ -4,8 +4,7 @@ import org.briarproject.bramble.BrambleAndroidModule;
import org.briarproject.bramble.BrambleCoreModule;
import org.briarproject.bramble.account.BriarAccountModule;
import org.briarproject.briar.BriarCoreModule;
-import org.briarproject.briar.android.login.SetupActivityScreenshotTest;
-import org.briarproject.briar.android.navdrawer.NavDrawerActivityTest;
+import org.briarproject.briar.android.contact.ConversationActivityScreenshotTest;
import org.briarproject.briar.android.settings.SettingsActivityScreenshotTest;
import javax.inject.Singleton;
@@ -22,8 +21,9 @@ import dagger.Component;
})
public interface BriarUiTestComponent extends AndroidComponent {
- void inject(SetupActivityScreenshotTest test);
- void inject(NavDrawerActivityTest test);
+ void inject(SetupDataTest test);
+
+ void inject(ConversationActivityScreenshotTest test);
void inject(SettingsActivityScreenshotTest test);
}
diff --git a/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/ScreenshotTest.java b/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/ScreenshotTest.java
new file mode 100644
index 000000000..2fcaf9c2e
--- /dev/null
+++ b/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/ScreenshotTest.java
@@ -0,0 +1,45 @@
+package org.briarproject.briar.android;
+
+import android.app.Activity;
+import android.util.Log;
+
+import org.briarproject.bramble.api.plugin.ConnectionRegistry;
+import org.briarproject.bramble.api.system.Clock;
+import org.briarproject.briar.api.test.TestDataCreator;
+import org.junit.ClassRule;
+
+import javax.inject.Inject;
+
+import tools.fastlane.screengrab.FalconScreenshotStrategy;
+import tools.fastlane.screengrab.Screengrab;
+import tools.fastlane.screengrab.locale.LocaleTestRule;
+
+public abstract class ScreenshotTest extends UiTest {
+
+ @ClassRule
+ public static final LocaleTestRule localeTestRule = new LocaleTestRule();
+
+ @Inject
+ protected TestDataCreator testDataCreator;
+ @Inject
+ protected ConnectionRegistry connectionRegistry;
+ @Inject
+ protected Clock clock;
+
+ protected void screenshot(String name, Activity activity) {
+ try {
+ Screengrab.screenshot(name, new FalconScreenshotStrategy(activity));
+ } catch (RuntimeException e) {
+ if (!e.getMessage().equals("Unable to capture screenshot."))
+ throw e;
+ // The tests should still pass when run from AndroidStudio
+ // without manually granting permissions like fastlane does.
+ Log.w("Screengrab", "Permission to write screenshot is missing.");
+ }
+ }
+
+ protected long getMinutesAgo(int minutes) {
+ return clock.currentTimeMillis() - minutes * 60 * 1000;
+ }
+
+}
diff --git a/briar-android/src/androidTest/java/org/briarproject/briar/android/login/SetupActivityScreenshotTest.java b/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/SetupDataTest.java
similarity index 62%
rename from briar-android/src/androidTest/java/org/briarproject/briar/android/login/SetupActivityScreenshotTest.java
rename to briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/SetupDataTest.java
index 475ae87a1..53b5d308f 100644
--- a/briar-android/src/androidTest/java/org/briarproject/briar/android/login/SetupActivityScreenshotTest.java
+++ b/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/SetupDataTest.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android;
import android.support.test.espresso.intent.rule.IntentsTestRule;
import android.support.test.runner.AndroidJUnit4;
@@ -6,9 +6,12 @@ import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiSelector;
+import org.briarproject.bramble.api.FormatException;
+import org.briarproject.bramble.api.contact.Contact;
+import org.briarproject.bramble.api.db.DbException;
import org.briarproject.briar.R;
-import org.briarproject.briar.android.BriarUiTestComponent;
-import org.briarproject.briar.android.test.ScreenshotTest;
+import org.briarproject.briar.android.login.OpenDatabaseActivity;
+import org.briarproject.briar.android.login.SetupActivity;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -26,14 +29,14 @@ import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static android.support.test.runner.lifecycle.Stage.PAUSED;
-import static junit.framework.Assert.assertTrue;
-import static org.briarproject.briar.android.test.ViewActions.waitForActivity;
-import static org.briarproject.briar.android.test.ViewActions.waitUntilMatches;
+import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
+import static org.briarproject.briar.android.ViewActions.waitForActivity;
+import static org.briarproject.briar.android.ViewActions.waitUntilMatches;
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
-
+import static org.junit.Assert.assertTrue;
@RunWith(AndroidJUnit4.class)
-public class SetupActivityScreenshotTest extends ScreenshotTest {
+public class SetupDataTest extends ScreenshotTest {
@Rule
public IntentsTestRule testRule =
@@ -61,7 +64,7 @@ public class SetupActivityScreenshotTest extends ScreenshotTest {
onView(withId(R.id.nickname_entry))
.perform(waitUntilMatches(withText(USERNAME)));
- screenshot("manual_create_account");
+ screenshot("manual_create_account", testRule.getActivity());
onView(withId(R.id.next))
.check(matches(isDisplayed()))
@@ -94,13 +97,54 @@ public class SetupActivityScreenshotTest extends ScreenshotTest {
}
// wait for OpenDatabaseActivity to show up
- onView(withId(R.id.progress))
- .check(matches(isDisplayed()));
onView(isRoot())
.perform(waitForActivity(testRule.getActivity(), PAUSED));
intended(hasComponent(OpenDatabaseActivity.class.getName()));
assertTrue(accountManager.hasDatabaseKey());
+
+ lifecycleManager.waitForStartup();
+ createTestData();
+
+ // close expiry warning
+ onView(withId(R.id.expiryWarning))
+ .perform(waitUntilMatches(isDisplayed()));
+ onView(withId(R.id.expiryWarningClose))
+ .check(matches(isDisplayed()));
+ onView(withId(R.id.expiryWarningClose))
+ .perform(click());
+ }
+
+ private void createTestData() {
+ try {
+ createTestDataExceptions();
+ } catch (DbException | FormatException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private void createTestDataExceptions()
+ throws DbException, FormatException {
+ String bobName =
+ getTargetContext().getString(R.string.screenshot_bob);
+ Contact bob = testDataCreator.addContact(bobName);
+
+ String bobHi = getTargetContext()
+ .getString(R.string.screenshot_message_1);
+ long bobTime = getMinutesAgo(2);
+ testDataCreator.addPrivateMessage(bob, bobHi, bobTime, true);
+
+ String aliceHi = getTargetContext()
+ .getString(R.string.screenshot_message_2);
+ long aliceTime = getMinutesAgo(1);
+ testDataCreator.addPrivateMessage(bob, aliceHi, aliceTime, false);
+
+ String bobHi2 = getTargetContext()
+ .getString(R.string.screenshot_message_3);
+ long bobTime2 = getMinutesAgo(0);
+ testDataCreator.addPrivateMessage(bob, bobHi2, bobTime2, true);
+
+ connectionRegistry.registerConnection(bob.getId(), ID, true);
}
}
diff --git a/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/contact/ConversationActivityScreenshotTest.java b/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/contact/ConversationActivityScreenshotTest.java
new file mode 100644
index 000000000..e25951c33
--- /dev/null
+++ b/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/contact/ConversationActivityScreenshotTest.java
@@ -0,0 +1,52 @@
+package org.briarproject.briar.android.contact;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.briarproject.briar.R;
+import org.briarproject.briar.android.BriarUiTestComponent;
+import org.briarproject.briar.android.ScreenshotTest;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.InstrumentationRegistry.getInstrumentation;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static org.briarproject.briar.android.ViewActions.waitUntilMatches;
+import static org.briarproject.briar.android.contact.ConversationActivity.CONTACT_ID;
+import static org.hamcrest.Matchers.allOf;
+
+@RunWith(AndroidJUnit4.class)
+public class ConversationActivityScreenshotTest extends ScreenshotTest {
+
+ @Rule
+ public ActivityTestRule testRule =
+ new ActivityTestRule<>(ConversationActivity.class, false, false);
+
+ @Override
+ protected void inject(BriarUiTestComponent component) {
+ component.inject(this);
+ }
+
+ @Test
+ public void messaging() throws Exception {
+ Context targetContext = getInstrumentation().getTargetContext();
+ Intent intent = new Intent(targetContext, ConversationActivity.class);
+ intent.putExtra(CONTACT_ID, 1);
+ testRule.launchActivity(intent);
+
+ onView(withId(R.id.conversationView))
+ .perform(waitUntilMatches(allOf(
+ withText(R.string.screenshot_message_3),
+ isCompletelyDisplayed())
+ ));
+
+ screenshot("manual_messaging", testRule.getActivity());
+ }
+
+}
diff --git a/briar-android/src/androidTest/java/org/briarproject/briar/android/settings/SettingsActivityScreenshotTest.java b/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/settings/SettingsActivityScreenshotTest.java
similarity index 77%
rename from briar-android/src/androidTest/java/org/briarproject/briar/android/settings/SettingsActivityScreenshotTest.java
rename to briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/settings/SettingsActivityScreenshotTest.java
index 34621c394..ceb1817f6 100644
--- a/briar-android/src/androidTest/java/org/briarproject/briar/android/settings/SettingsActivityScreenshotTest.java
+++ b/briar-android/src/androidTestScreenshot/java/org/briarproject/briar/android/settings/SettingsActivityScreenshotTest.java
@@ -2,14 +2,15 @@ package org.briarproject.briar.android.settings;
import android.content.Intent;
import android.support.test.espresso.contrib.DrawerActions;
+import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import org.briarproject.briar.R;
import org.briarproject.briar.android.BriarUiTestComponent;
+import org.briarproject.briar.android.ScreenshotTest;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
-import org.briarproject.briar.android.test.ScreenshotTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -26,15 +27,15 @@ import static android.support.test.espresso.matcher.ViewMatchers.withChild;
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static org.briarproject.briar.android.test.ViewActions.waitUntilMatches;
+import static org.briarproject.briar.android.ViewActions.waitUntilMatches;
import static org.hamcrest.CoreMatchers.is;
@RunWith(AndroidJUnit4.class)
public class SettingsActivityScreenshotTest extends ScreenshotTest {
@Rule
- public CleanAccountTestRule testRule =
- new CleanAccountTestRule<>(SettingsActivity.class);
+ public ActivityTestRule testRule =
+ new ActivityTestRule<>(SettingsActivity.class);
@Override
protected void inject(BriarUiTestComponent component) {
@@ -46,7 +47,7 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
onView(withText(R.string.settings_button))
.check(matches(isDisplayed()));
- screenshot("manual_dark_theme_settings");
+ screenshot("manual_dark_theme_settings", testRule.getActivity());
// switch to dark theme
onView(withText(R.string.pref_theme_title))
@@ -56,10 +57,20 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
.check(matches(isDisplayed()))
.perform(click());
- // open nav drawer and remove expiry warning
- openNavDrawer(true);
+ openNavDrawer();
- screenshot("manual_dark_theme_nav_drawer");
+ screenshot("manual_dark_theme_nav_drawer", testRule.getActivity());
+
+ // switch to back to light theme
+ onView(withText(R.string.settings_button))
+ .check(matches(isDisplayed()))
+ .perform(click());
+ onView(withText(R.string.pref_theme_title))
+ .check(matches(isDisplayed()))
+ .perform(click());
+ onView(withText(R.string.pref_theme_light))
+ .check(matches(isDisplayed()))
+ .perform(click());
}
@Test
@@ -83,12 +94,11 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
.check(matches(isDisplayed()))
.check(matches(isEnabled()));
- screenshot("manual_app_lock");
+ screenshot("manual_app_lock", testRule.getActivity());
- // no more expiry warning to remove, because sharedprefs cached?
- openNavDrawer(false);
+ openNavDrawer();
- screenshot("manual_app_lock_nav_drawer");
+ screenshot("manual_app_lock_nav_drawer", testRule.getActivity());
}
@Test
@@ -104,23 +114,15 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
.check(matches(isDisplayed()))
.perform(waitUntilMatches(isEnabled()));
- screenshot("manual_tor_settings");
+ screenshot("manual_tor_settings", testRule.getActivity());
}
- private void openNavDrawer(boolean expiry) {
+ private void openNavDrawer() {
// start main activity
Intent i =
new Intent(testRule.getActivity(), NavDrawerActivity.class);
testRule.getActivity().startActivity(i);
- // close expiry warning
- if (expiry) {
- onView(withId(R.id.expiryWarningClose))
- .check(matches(isDisplayed()));
- onView(withId(R.id.expiryWarningClose))
- .perform(click());
- }
-
// open navigation drawer
onView(withId(R.id.drawer_layout))
.check(matches(isClosed(Gravity.START)))
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index 2a63f683f..08afd7f57 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -480,4 +480,20 @@
Briar is locked
Tap to unlock
+
+
+
+ Alice
+
+ Bob
+
+ Carol
+
+ Hi Bob!
+
+ Hi Alice! Thanks for telling me about Briar!
+
+ No problem, hope you like it 😀
+
+
diff --git a/briar-android/witness.gradle b/briar-android/witness.gradle
index 2a5727a16..0fa29a1f9 100644
--- a/briar-android/witness.gradle
+++ b/briar-android/witness.gradle
@@ -82,6 +82,7 @@ dependencyVerification {
'com.google.zxing:core:3.3.0:core-3.3.0.jar:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.ibm.icu:icu4j:53.1:icu4j-53.1.jar:e37a4467bac5cdeb02c5c4b8e5063d2f4e67b69e3c7df6d6b610f13185572bab',
+ 'com.jraska:falcon:1.0.4:falcon-1.0.4.aar:6114a48d8b3814f75fc69b5e84dc087c1254883874eae8a36bd778979800630a',
'com.squareup:javawriter:2.1.1:javawriter-2.1.1.jar:f699823d0081f69cbb676c1845ea222e0ada79bc88a53e5d22d8bd02d328f57e',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
@@ -171,7 +172,7 @@ dependencyVerification {
'org.robolectric:shadows-framework:3.8:shadows-framework-3.8.jar:83548db7249edf1af87e1a1f4d8f4eec3e85d6220161da601e6f6398476911b2',
'org.robolectric:shadows-support-v4:3.3.2:shadows-support-v4-3.3.2.jar:6f689264738266e70fe08db7c04b7b5a75155994f4e3f7f311960d90486bf005',
'org.robolectric:utils:3.8:utils-3.8.jar:e945d04d40e37554e02d4be1bc3abf9bede45375c843aa36d10ccb6b63edbf34',
- 'tools.fastlane:screengrab:1.1.0:screengrab-1.1.0.aar:03ce3868ee8a0082d14e7a1de0999f91531c0cc794392688beb08ee9bc4495fd',
+ 'tools.fastlane:screengrab:1.2.0:screengrab-1.2.0.aar:af4ee23bb06f94404d3ab18e2ea69db8265539fc8da29f9ee45b7e472684ba83',
'uk.co.samuelwall:material-tap-target-prompt:2.8.0:material-tap-target-prompt-2.8.0.aar:ac70770c05bbc4675a1d5712c0e53d46ee4fa961b74947589fce50d8003065ec',
'xmlpull:xmlpull:1.1.3.1:xmlpull-1.1.3.1.jar:34e08ee62116071cbb69c0ed70d15a7a5b208d62798c59f2120bb8929324cb63',
'xpp3:xpp3_min:1.1.4c:xpp3_min-1.1.4c.jar:bfc90e9e32d0eab1f397fb974b5f150a815188382ac41f372a7149d5bc178008',
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/test/TestDataCreator.java b/briar-api/src/main/java/org/briarproject/briar/api/test/TestDataCreator.java
index fc210e583..fe1178307 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/test/TestDataCreator.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/test/TestDataCreator.java
@@ -1,12 +1,16 @@
package org.briarproject.briar.api.test;
+import org.briarproject.bramble.api.FormatException;
+import org.briarproject.bramble.api.contact.Contact;
+import org.briarproject.bramble.api.db.DbException;
+import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface TestDataCreator {
/**
- * Create fake test data on the DatabaseExecutor
+ * Create fake test data on the IoExecutor
*
* @param numContacts Number of contacts to create. Must be >= 1
* @param numPrivateMsgs Number of private messages to create for each
@@ -18,4 +22,11 @@ public interface TestDataCreator {
void createTestData(int numContacts, int numPrivateMsgs, int numBlogPosts,
int numForums, int numForumPosts);
+ @IoExecutor
+ Contact addContact(String name) throws DbException;
+
+ @IoExecutor
+ void addPrivateMessage(Contact contact, String body, long time,
+ boolean local) throws DbException, FormatException;
+
}
diff --git a/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java b/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java
index fd66761ea..6b2dbc243 100644
--- a/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java
@@ -13,9 +13,11 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.AuthorFactory;
+import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
+import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.BluetoothConstants;
import org.briarproject.bramble.api.plugin.LanTcpConstants;
import org.briarproject.bramble.api.plugin.TorConstants;
@@ -59,6 +61,7 @@ import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.briarproject.briar.test.TestData.AUTHOR_NAMES;
import static org.briarproject.briar.test.TestData.GROUP_NAMES;
+@NotNullByDefault
public class TestDataCreatorImpl implements TestDataCreator {
private final Logger LOG =
@@ -146,17 +149,17 @@ public class TestDataCreatorImpl implements TestDataCreator {
List contacts = new ArrayList<>(numContacts);
LocalAuthor localAuthor = identityManager.getLocalAuthor();
for (int i = 0; i < numContacts; i++) {
- Contact contact = addRandomContact(localAuthor);
+ LocalAuthor author = getRandomAuthor();
+ Contact contact = addContact(localAuthor.getId(), author);
contacts.add(contact);
}
return contacts;
}
- private Contact addRandomContact(LocalAuthor localAuthor)
+ private Contact addContact(AuthorId localAuthorId, LocalAuthor author)
throws DbException {
// prepare to add contact
- LocalAuthor author = getRandomAuthor();
SecretKey secretKey = getSecretKey();
long timestamp = clock.currentTimeMillis();
boolean verified = random.nextBoolean();
@@ -169,7 +172,7 @@ public class TestDataCreatorImpl implements TestDataCreator {
Transaction txn = db.startTransaction(false);
try {
ContactId contactId = contactManager
- .addContact(txn, author, localAuthor.getId(), secretKey,
+ .addContact(txn, author, localAuthorId, secretKey,
timestamp, true, verified, true);
transportPropertyManager.addRemoteProperties(txn, contactId, props);
contact = db.getContact(txn, contactId);
@@ -186,14 +189,23 @@ public class TestDataCreatorImpl implements TestDataCreator {
return contact;
}
- private LocalAuthor getRandomAuthor() {
- int i = random.nextInt(AUTHOR_NAMES.length);
- String authorName = AUTHOR_NAMES[i];
+ @Override
+ public Contact addContact(String name) throws DbException {
+ LocalAuthor localAuthor = identityManager.getLocalAuthor();
+ return addContact(localAuthor.getId(), getAuthor(name));
+ }
+
+ private LocalAuthor getAuthor(String name) {
KeyPair keyPair = cryptoComponent.generateSignatureKeyPair();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();
- return authorFactory.createLocalAuthor(authorName, publicKey,
- privateKey);
+ return authorFactory.createLocalAuthor(name, publicKey, privateKey);
+ }
+
+ private LocalAuthor getRandomAuthor() {
+ int i = random.nextInt(AUTHOR_NAMES.length);
+ String authorName = AUTHOR_NAMES[i];
+ return getAuthor(authorName);
}
private SecretKey getSecretKey() {
@@ -285,7 +297,7 @@ public class TestDataCreatorImpl implements TestDataCreator {
Group group = messagingManager.getContactGroup(contact);
for (int i = 0; i < numPrivateMsgs; i++) {
try {
- createPrivateMessage(group.getId(), i);
+ createRandomPrivateMessage(group.getId(), i);
} catch (FormatException e) {
throw new RuntimeException(e);
}
@@ -297,14 +309,18 @@ public class TestDataCreatorImpl implements TestDataCreator {
}
}
- private void createPrivateMessage(GroupId groupId, int num)
+ private void createRandomPrivateMessage(GroupId groupId, int num)
throws DbException, FormatException {
long timestamp = clock.currentTimeMillis() - num * 60 * 1000;
String body = getRandomText();
+ boolean local = random.nextBoolean();
+ createPrivateMessage(groupId, body, timestamp, local);
+ }
+
+ private void createPrivateMessage(GroupId groupId, String body,
+ long timestamp, boolean local) throws DbException, FormatException {
PrivateMessage m = privateMessageFactory
.createPrivateMessage(groupId, timestamp, body);
-
- boolean local = random.nextBoolean();
BdfDictionary meta = new BdfDictionary();
meta.put("timestamp", timestamp);
meta.put("local", local);
@@ -321,6 +337,13 @@ public class TestDataCreatorImpl implements TestDataCreator {
}
}
+ @Override
+ public void addPrivateMessage(Contact contact, String body, long time,
+ boolean local) throws DbException, FormatException {
+ Group group = messagingManager.getContactGroup(contact);
+ createPrivateMessage(group.getId(), body, time, local);
+ }
+
private void createBlogPosts(List contacts, int numBlogPosts)
throws DbException {
for (int i = 0; i < numBlogPosts; i++) {