diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..9508829155633f174655970829fae61c8837621e --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,20 @@ +image: registry.gitlab.com/fdroid/ci-images:client-latest + +cache: + paths: + - .gradle/wrapper + - .gradle/caches + +before_script: + - export GRADLE_USER_HOME=$PWD/.gradle +# - export ANDROID_COMPILE_SDK=`sed -n 's,.*compileSdkVersion\s*\([0-9][0-9]*\).*,\1,p' app/build.gradle` +# - echo y | android --silent update sdk --no-ui --filter android-${ANDROID_COMPILE_SDK} + +test: + script: + - ./gradlew test + +after_script: + # this file changes every time but should not be cached + - rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock + - rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/ diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java index 5ab9594f8ba20f188eb0f6f3acb4f3a8365058c1..639155ac4aa6dc3d9d2885f9480e1e56ae557136 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java @@ -8,6 +8,7 @@ public interface TorConstants { int CONTROL_PORT = 59051; int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds + int EXTRA_SOCKET_TIMEOUT = 30000; // Milliseconds String PREF_TOR_NETWORK = "network"; String PREF_TOR_PORT = "port"; diff --git a/bramble-api/src/main/java/org/briarproject/bramble/util/PrivacyUtils.java b/bramble-api/src/main/java/org/briarproject/bramble/util/PrivacyUtils.java index 50c4e792a2d942df4eb55e3651555593ea605863..9156b9caafa77e3d3560eee47ddfc8d67ef28521 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/util/PrivacyUtils.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/util/PrivacyUtils.java @@ -19,7 +19,7 @@ public class PrivacyUtils { @Nullable public static String scrubMacAddress(@Nullable String address) { - if (address == null) return null; + if (address == null || address.length() == 0) return null; // this is a fake address we need to know about if (address.equals("02:00:00:00:00:00")) return address; // keep first and last octet of MAC address diff --git a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksModule.java b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksModule.java index 1fe9f31c6fb7c3623e7ce4dcc4081a0dd86614e5..be342f0110bc34d6353f54948cccd3945c798a1c 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksModule.java @@ -8,6 +8,7 @@ import dagger.Module; import dagger.Provides; import static org.briarproject.bramble.api.plugin.TorConstants.CONNECT_TO_PROXY_TIMEOUT; +import static org.briarproject.bramble.api.plugin.TorConstants.EXTRA_SOCKET_TIMEOUT; import static org.briarproject.bramble.api.plugin.TorConstants.SOCKS_PORT; @Module @@ -17,6 +18,7 @@ public class SocksModule { SocketFactory provideTorSocketFactory() { InetSocketAddress proxy = new InetSocketAddress("127.0.0.1", SOCKS_PORT); - return new SocksSocketFactory(proxy, CONNECT_TO_PROXY_TIMEOUT); + return new SocksSocketFactory(proxy, CONNECT_TO_PROXY_TIMEOUT, + EXTRA_SOCKET_TIMEOUT); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocket.java b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocket.java index 9494e629773ce2768b0d583babc78eb007e1cfb7..7f5cb0090db1fa56102c24a9ce7c5328fe27e896 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocket.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocket.java @@ -29,11 +29,13 @@ class SocksSocket extends Socket { private static final byte[] UNSPECIFIED_ADDRESS = new byte[4]; private final SocketAddress proxy; - private final int connectToProxyTimeout; + private final int connectToProxyTimeout, extraSocketTimeout; - SocksSocket(SocketAddress proxy, int connectToProxyTimeout) { + SocksSocket(SocketAddress proxy, int connectToProxyTimeout, + int extraSocketTimeout) { this.proxy = proxy; this.connectToProxyTimeout = connectToProxyTimeout; + this.extraSocketTimeout = extraSocketTimeout; } @Override @@ -47,7 +49,7 @@ class SocksSocket extends Socket { InetAddress address = inet.getAddress(); if (address != null && !Arrays.equals(address.getAddress(), UNSPECIFIED_ADDRESS)) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException(); } String host = inet.getHostName(); if (host.length() > 255) throw new IllegalArgumentException(); @@ -62,16 +64,16 @@ class SocksSocket extends Socket { sendMethodRequest(out); receiveMethodResponse(in); - // Use the supplied timeout temporarily + // Use the supplied timeout temporarily, plus any configured extra int oldTimeout = getSoTimeout(); - setSoTimeout(timeout); + setSoTimeout(timeout + extraSocketTimeout); // Connect to the endpoint via the proxy sendConnectRequest(out, host, port); receiveConnectResponse(in); - // Restore the old timeout - setSoTimeout(oldTimeout); + // Restore the old timeout, plus any configured extra + setSoTimeout(oldTimeout + extraSocketTimeout); } private void sendMethodRequest(OutputStream out) throws IOException { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocketFactory.java b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocketFactory.java index adc5265fb989256aca09cfbfb8a7e408d55730d0..fb0b1cd916d8b297cc794628b0d8a7ce19780eed 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocketFactory.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocketFactory.java @@ -11,16 +11,18 @@ import javax.net.SocketFactory; class SocksSocketFactory extends SocketFactory { private final SocketAddress proxy; - private final int connectToProxyTimeout; + private final int connectToProxyTimeout, extraSocketTimeout; - SocksSocketFactory(SocketAddress proxy, int connectToProxyTimeout) { + SocksSocketFactory(SocketAddress proxy, int connectToProxyTimeout, + int extraSocketTimeout) { this.proxy = proxy; this.connectToProxyTimeout = connectToProxyTimeout; + this.extraSocketTimeout = extraSocketTimeout; } @Override public Socket createSocket() { - return new SocksSocket(proxy, connectToProxyTimeout); + return new SocksSocket(proxy, connectToProxyTimeout, extraSocketTimeout); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index 9923043643e8983be4adc12d72877df2e5337b7b..9394f9d02ee249fc0bf9495e4f00df3fc6cb343b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -32,6 +32,7 @@ import org.briarproject.briar.api.android.ScreenFilterMonitor; import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogPostFactory; import org.briarproject.briar.api.blog.BlogSharingManager; +import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.feed.FeedManager; import org.briarproject.briar.api.forum.ForumManager; import org.briarproject.briar.api.forum.ForumSharingManager; @@ -78,6 +79,8 @@ public interface AndroidComponent @DatabaseExecutor Executor databaseExecutor(); + MessageTracker messageTracker(); + LifecycleManager lifecycleManager(); IdentityManager identityManager(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java index c4560809437209e6a112d19d7da3c5800a6eb1f7..003c77ee762786da489dc2ce6ce95696403e583e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java @@ -59,7 +59,6 @@ import static android.app.Notification.DEFAULT_SOUND; import static android.app.Notification.DEFAULT_VIBRATE; import static android.content.Context.NOTIFICATION_SERVICE; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; -import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE; import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL; import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET; @@ -310,7 +309,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, ContactId c = contactCounts.keySet().iterator().next(); i.putExtra(CONTACT_ID, c.getInt()); i.setData(Uri.parse(CONTACT_URI + "/" + c.getInt())); - i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(ConversationActivity.class); t.addNextIntent(i); @@ -319,7 +318,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, // Touching the notification shows the contact list Intent i = new Intent(appContext, NavDrawerActivity.class); i.putExtra(INTENT_CONTACTS, true); - i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); i.setData(Uri.parse(CONTACT_URI)); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(NavDrawerActivity.class); @@ -415,7 +414,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, i.putExtra(GROUP_ID, g.getBytes()); String idHex = StringUtils.toHexString(g.getBytes()); i.setData(Uri.parse(GROUP_URI + "/" + idHex)); - i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(GroupActivity.class); t.addNextIntent(i); @@ -424,7 +423,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, // Touching the notification shows the group list Intent i = new Intent(appContext, NavDrawerActivity.class); i.putExtra(INTENT_GROUPS, true); - i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); i.setData(Uri.parse(GROUP_URI)); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(NavDrawerActivity.class); @@ -507,7 +506,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, i.putExtra(GROUP_ID, g.getBytes()); String idHex = StringUtils.toHexString(g.getBytes()); i.setData(Uri.parse(FORUM_URI + "/" + idHex)); - i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(ForumActivity.class); t.addNextIntent(i); @@ -516,7 +515,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, // Touching the notification shows the forum list Intent i = new Intent(appContext, NavDrawerActivity.class); i.putExtra(INTENT_FORUMS, true); - i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); i.setData(Uri.parse(FORUM_URI)); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(NavDrawerActivity.class); @@ -595,7 +594,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, // Touching the notification shows the combined blog feed Intent i = new Intent(appContext, NavDrawerActivity.class); i.putExtra(INTENT_BLOGS, true); - i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); i.setData(Uri.parse(BLOG_URI)); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(NavDrawerActivity.class); @@ -651,7 +650,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, // Touching the notification shows the contact list Intent i = new Intent(appContext, NavDrawerActivity.class); i.putExtra(INTENT_CONTACTS, true); - i.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); i.setData(Uri.parse(CONTACT_URI)); TaskStackBuilder t = TaskStackBuilder.create(appContext); t.addParentStack(NavDrawerActivity.class); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java index e273d393d62960e129a06465fb024dc63736f77e..9c12a7ace5cb929d46a0efa531d81630884229b0 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java @@ -28,7 +28,6 @@ import javax.inject.Inject; import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; -import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE; import static android.support.v4.app.NotificationCompat.PRIORITY_MIN; import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET; @@ -83,8 +82,7 @@ public class BriarService extends Service { b.setWhen(0); // Don't show the time b.setOngoing(true); Intent i = new Intent(this, NavDrawerActivity.class); - i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP | - FLAG_ACTIVITY_SINGLE_TOP); + i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP); b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0)); if (Build.VERSION.SDK_INT >= 21) { b.setCategory(CATEGORY_SERVICE); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/ScreenFilterMonitorImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/ScreenFilterMonitorImpl.java index cb195108af4f941db686df4c512cb05cd6601b31..6acf7525572ff85f550a168a070c0f5df527a5e3 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/ScreenFilterMonitorImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/ScreenFilterMonitorImpl.java @@ -6,11 +6,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.Signature; import android.support.annotation.UiThread; import android.support.v7.preference.PreferenceManager; @@ -19,11 +18,16 @@ import org.briarproject.bramble.api.lifecycle.ServiceException; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.util.StringUtils; import org.briarproject.briar.api.android.ScreenFilterMonitor; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.util.Collection; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -31,32 +35,58 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.Level; import java.util.logging.Logger; +import javax.annotation.Nullable; import javax.inject.Inject; import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; +import static android.content.Intent.ACTION_PACKAGE_ADDED; +import static android.content.Intent.EXTRA_REPLACING; +import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; +import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; +import static android.content.pm.PackageManager.GET_PERMISSIONS; +import static android.content.pm.PackageManager.GET_SIGNATURES; +import static java.util.logging.Level.WARNING; @MethodsNotNullByDefault @ParametersNotNullByDefault public class ScreenFilterMonitorImpl extends BroadcastReceiver - implements Service, - ScreenFilterMonitor { + implements Service, ScreenFilterMonitor { private static final Logger LOG = Logger.getLogger(ScreenFilterMonitorImpl.class.getName()); private static final String PREF_SCREEN_FILTER_APPS = "shownScreenFilterApps"; + + /* + * Ignore Play Services if it uses this package name and public key - it's + * effectively a system app, but not flagged as such on older systems + */ + private static final String PLAY_SERVICES_PACKAGE = + "com.google.android.gms"; + private static final String PLAY_SERVICES_PUBLIC_KEY = + "30820120300D06092A864886F70D01010105000382010D0030820108" + + "0282010100AB562E00D83BA208AE0A966F124E29DA11F2AB56D08F58" + + "E2CCA91303E9B754D372F640A71B1DCB130967624E4656A7776A9219" + + "3DB2E5BFB724A91E77188B0E6A47A43B33D9609B77183145CCDF7B2E" + + "586674C9E1565B1F4C6A5955BFF251A63DABF9C55C27222252E875E4" + + "F8154A645F897168C0B1BFC612EABF785769BB34AA7984DC7E2EA276" + + "4CAE8307D8C17154D7EE5F64A51A44A602C249054157DC02CD5F5C0E" + + "55FBEF8519FBE327F0B1511692C5A06F19D18385F5C4DBC2D6B93F68" + + "CC2979C70E18AB93866B3BD5DB8999552A0E3B4C99DF58FB918BEDC1" + + "82BA35E003C1B4B10DD244A8EE24FFFD333872AB5221985EDAB0FC0D" + + "0B145B6AA192858E79020103"; + private final Context appContext; private final AndroidExecutor androidExecutor; - private final LinkedList<String> appNames = new LinkedList<>(); private final PackageManager pm; private final SharedPreferences prefs; private final AtomicBoolean used = new AtomicBoolean(false); + + // The following must only be accessed on the UI thread private final Set<String> apps = new HashSet<>(); private final Set<String> shownApps; - // Used solely for the UiThread private boolean serviceStarted = false; @Inject @@ -75,7 +105,7 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver @Override public Void call() { IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + intentFilter.addAction(ACTION_PACKAGE_ADDED); intentFilter.addDataScheme("package"); appContext.registerReceiver(ScreenFilterMonitorImpl.this, intentFilter); @@ -109,9 +139,8 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver } private Set<String> getShownScreenFilterApps() { - // res must not be modified - Set<String> s = - prefs.getStringSet(PREF_SCREEN_FILTER_APPS, null); + // Result must not be modified + Set<String> s = prefs.getStringSet(PREF_SCREEN_FILTER_APPS, null); HashSet<String> result = new HashSet<>(); if (s != null) { result.addAll(s); @@ -121,7 +150,7 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver @Override public void onReceive(Context context, Intent intent) { - if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + if (!intent.getBooleanExtra(EXTRA_REPLACING, false)) { final String packageName = intent.getData().getEncodedSchemeSpecificPart(); androidExecutor.runOnUiThread(new Runnable() { @@ -155,7 +184,7 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver @Override @UiThread public void storeAppsAsShown(Collection<String> s, boolean persistent) { - HashSet<String> buf = new HashSet(s); + HashSet<String> buf = new HashSet<>(s); shownApps.addAll(buf); if (persistent && !s.isEmpty()) { buf.addAll(getShownScreenFilterApps()); @@ -168,7 +197,7 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver private Set<String> getInstalledScreenFilterApps() { HashSet<String> screenFilterApps = new HashSet<>(); List<PackageInfo> packageInfos = - pm.getInstalledPackages(PackageManager.GET_PERMISSIONS); + pm.getInstalledPackages(GET_PERMISSIONS); for (PackageInfo packageInfo : packageInfos) { if (isOverlayApp(packageInfo)) { String name = pkgToString(packageInfo); @@ -180,25 +209,22 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver return screenFilterApps; } - // Checks if pkg uses the SYSTEM_ALERT_WINDOW permission and if so + // Checks if a package uses the SYSTEM_ALERT_WINDOW permission and if so // returns the app name. @Nullable private String isOverlayApp(String pkg) { try { - PackageInfo pkgInfo = - pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS); + PackageInfo pkgInfo = pm.getPackageInfo(pkg, GET_PERMISSIONS); if (isOverlayApp(pkgInfo)) { return pkgToString(pkgInfo); } - } catch (PackageManager.NameNotFoundException ignored) { - if (LOG.isLoggable(Level.WARNING)) { - LOG.warning("Package name not found: " + pkg); - } + } catch (NameNotFoundException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } return null; } - // Fetch the application name for a given package. + // Fetches the application name for a given package. @Nullable private String pkgToString(PackageInfo pkgInfo) { CharSequence seq = pm.getApplicationLabel(pkgInfo.applicationInfo); @@ -208,25 +234,49 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver return null; } - // Checks if an installed pkg is a user app using the permission. + // Checks if an installed package is a user app using the permission. private boolean isOverlayApp(PackageInfo packageInfo) { - int mask = ApplicationInfo.FLAG_SYSTEM | - ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + int mask = FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP; // Ignore system apps if ((packageInfo.applicationInfo.flags & mask) != 0) { return false; } - //Get Permissions - String[] requestedPermissions = - packageInfo.requestedPermissions; + // Ignore Play Services, it's effectively a system app + if (isPlayServices(packageInfo.packageName)) { + return false; + } + // Get permissions + String[] requestedPermissions = packageInfo.requestedPermissions; if (requestedPermissions != null) { for (String requestedPermission : requestedPermissions) { - if (requestedPermission - .equals(SYSTEM_ALERT_WINDOW)) { + if (requestedPermission.equals(SYSTEM_ALERT_WINDOW)) { return true; } } } return false; } + + private boolean isPlayServices(String pkg) { + if (!PLAY_SERVICES_PACKAGE.equals(pkg)) return false; + try { + PackageInfo sigs = pm.getPackageInfo(pkg, GET_SIGNATURES); + // The genuine Play Services app should have a single signature + Signature[] signatures = sigs.signatures; + if (signatures == null || signatures.length != 1) return false; + // Extract the public key from the signature + CertificateFactory certFactory = + CertificateFactory.getInstance("X509"); + byte[] signatureBytes = signatures[0].toByteArray(); + InputStream in = new ByteArrayInputStream(signatureBytes); + X509Certificate cert = + (X509Certificate) certFactory.generateCertificate(in); + byte[] publicKeyBytes = cert.getPublicKey().getEncoded(); + String publicKey = StringUtils.toHexString(publicKeyBytes); + return PLAY_SERVICES_PUBLIC_KEY.equals(publicKey); + } catch (NameNotFoundException | CertificateException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + return false; + } + } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java index 8178224499ebbf5f0945a18f129b919c42c7145c..e148db65b7c66379f74f9f94f5d40b420841cf17 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java @@ -3,7 +3,6 @@ package org.briarproject.briar.android.activity; import android.annotation.SuppressLint; import android.content.Intent; import android.os.Build; -import android.support.annotation.Nullable; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; import android.transition.Slide; @@ -21,6 +20,7 @@ import org.briarproject.briar.android.panic.ExitActivity; import java.util.logging.Logger; +import javax.annotation.Nullable; import javax.inject.Inject; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java index bfb689ef7013491aa1820ea4104a1a5135326bfb..5521b9bea4cbacae4635c12cfcff408dd08e40ed 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java @@ -2,7 +2,6 @@ package org.briarproject.briar.android.blog; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.support.v7.widget.Toolbar; import android.view.View; @@ -15,6 +14,7 @@ import org.briarproject.briar.android.activity.BriarActivity; import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.briar.android.sharing.BlogSharingStatusActivity; +import javax.annotation.Nullable; import javax.inject.Inject; @MethodsNotNullByDefault diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java index ae666f691a3b53a0fe82a6d51770a719cd372914..414420dbd2c7900de13abeed158e4a8c5fea943e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java @@ -169,7 +169,7 @@ class BlogControllerImpl extends BaseControllerImpl LocalAuthor a = identityManager.getLocalAuthor(); Blog b = blogManager.getBlog(groupId); boolean ours = a.getId().equals(b.getAuthor().getId()); - boolean removable = blogManager.canBeRemoved(groupId); + boolean removable = blogManager.canBeRemoved(b); BlogItem blog = new BlogItem(b, ours, removable); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java index e5cd225bc322c700c22b01368c27288a198361c8..c9305411d6a17a7e521d41f6fa29315abe105c53 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java @@ -43,7 +43,6 @@ import javax.inject.Inject; import static android.app.Activity.RESULT_OK; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; -import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; import static android.widget.Toast.LENGTH_SHORT; import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_SHARE_BLOG; @@ -149,14 +148,14 @@ public class BlogFragment extends BaseFragment return true; case R.id.action_blog_share: Intent i2 = new Intent(getActivity(), ShareBlogActivity.class); - i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP); i2.putExtra(GROUP_ID, groupId.getBytes()); startActivityForResult(i2, REQUEST_SHARE_BLOG); return true; case R.id.action_blog_sharing_status: Intent i3 = new Intent(getActivity(), BlogSharingStatusActivity.class); - i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP); i3.putExtra(GROUP_ID, groupId.getBytes()); startActivity(i3); return true; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactItemViewHolder.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactItemViewHolder.java index 33cf42232e734d4ef6f7c500b1d29ab5e84ada26..839c0563b79a5eeaaa48150935d6c2de0bc8272b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactItemViewHolder.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactItemViewHolder.java @@ -1,6 +1,5 @@ package org.briarproject.briar.android.contact; -import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -13,6 +12,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener; +import javax.annotation.Nullable; + import im.delight.android.identicons.IdenticonDrawable; @UiThread diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java index eaeb7a06ec1c15fbc58e42a2d27c03bb8124eda8..6ae01b8a53ad11cac4857179ccf52f41c9b577b2 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java @@ -17,7 +17,7 @@ public class DbControllerImpl implements DbController { private static final Logger LOG = Logger.getLogger(DbControllerImpl.class.getName()); - private final Executor dbExecutor; + protected final Executor dbExecutor; private final LifecycleManager lifecycleManager; @Inject diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/SharingControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/SharingControllerImpl.java index c41df9f238704a16784b2c8c9437a32b0f664146..5c83206e504ea690582d6390b2ba45524711acc9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/SharingControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/SharingControllerImpl.java @@ -1,7 +1,5 @@ package org.briarproject.briar.android.controller; -import android.support.annotation.Nullable; - import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.EventBus; @@ -15,6 +13,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; +import javax.annotation.Nullable; import javax.inject.Inject; @NotNullByDefault diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumActivity.java index ee82e165b72c986294b07b385d0866a90b24ae9e..2af57aa1a05779b4be53eae2000a02116ee118e4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumActivity.java @@ -34,7 +34,6 @@ import javax.annotation.Nullable; import javax.inject.Inject; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; -import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; import static android.widget.Toast.LENGTH_SHORT; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_SHARE_FORUM; import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH; @@ -117,18 +116,15 @@ public class ForumActivity extends public boolean onOptionsItemSelected(final MenuItem item) { // Handle presses on the action bar items switch (item.getItemId()) { - case R.id.action_forum_compose_post: - showTextInput(null); - return true; case R.id.action_forum_share: Intent i2 = new Intent(this, ShareForumActivity.class); - i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP); i2.putExtra(GROUP_ID, groupId.getBytes()); startActivityForResult(i2, REQUEST_SHARE_FORUM); return true; case R.id.action_forum_sharing_status: Intent i3 = new Intent(this, ForumSharingStatusActivity.class); - i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); + i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP); i3.putExtra(GROUP_ID, groupId.getBytes()); startActivity(i3); return true; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java index 4c52f6154c90103da580c4206ffc2dd3b4a882fb..8d97e7810063d4a4d20209a469220b5a2b7e8f47 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java @@ -17,6 +17,7 @@ import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import org.briarproject.briar.android.forum.ForumController.ForumListener; import org.briarproject.briar.android.threaded.ThreadListControllerImpl; import org.briarproject.briar.api.android.AndroidNotificationManager; +import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.ForumInvitationResponse; @@ -55,10 +56,10 @@ class ForumControllerImpl extends LifecycleManager lifecycleManager, IdentityManager identityManager, @CryptoExecutor Executor cryptoExecutor, ForumManager forumManager, ForumSharingManager forumSharingManager, - EventBus eventBus, Clock clock, + EventBus eventBus, Clock clock, MessageTracker messageTracker, AndroidNotificationManager notificationManager) { super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor, - eventBus, clock, notificationManager); + eventBus, clock, notificationManager, messageTracker); this.forumManager = forumManager; this.forumSharingManager = forumSharingManager; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/fragment/SFDialogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/fragment/SFDialogFragment.java index e20e814d685b249b2694aec1d85bf1ae6f33aa01..248d4c49ad7d914dceb5f26985b573ddf07bdaa8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/fragment/SFDialogFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/fragment/SFDialogFragment.java @@ -3,7 +3,6 @@ package org.briarproject.briar.android.fragment; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; -import android.support.annotation.Nullable; import android.support.v4.app.DialogFragment; import android.support.v7.app.AlertDialog; import android.text.TextUtils; @@ -19,6 +18,8 @@ import org.briarproject.briar.android.activity.BaseActivity; import java.util.ArrayList; +import javax.annotation.Nullable; + @MethodsNotNullByDefault @ParametersNotNullByDefault public class SFDialogFragment extends DialogFragment { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/fragment/SignOutFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/fragment/SignOutFragment.java index 7999679ae1fd8bcb71bb3427e573246b6e6061e6..8c014237a2055cd6fbeefd59e2ff3a58ce46c057 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/fragment/SignOutFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/fragment/SignOutFragment.java @@ -1,7 +1,6 @@ package org.briarproject.briar.android.fragment; import android.os.Bundle; -import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -9,6 +8,8 @@ import android.view.ViewGroup; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; +import javax.annotation.Nullable; + public class SignOutFragment extends BaseFragment { private static final String TAG = SignOutFragment.class.getName(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java index feaddbec9cadbc4f9faab0f839e79b04fe29826f..c19aa38a26730893fbce3ca2e73119f696688a7e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupActivity.java @@ -37,6 +37,7 @@ import javax.annotation.Nullable; import javax.inject.Inject; import static android.view.View.GONE; +import static android.view.View.VISIBLE; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_GROUP_INVITE; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_POST_BODY_LENGTH; @@ -50,8 +51,8 @@ public class GroupActivity extends GroupController controller; private boolean isCreator, isDissolved = false; - private MenuItem writeMenuItem, revealMenuItem, inviteMenuItem, - leaveMenuItem, dissolveMenuItem; + private MenuItem revealMenuItem, inviteMenuItem, leaveMenuItem, + dissolveMenuItem; @Override public void injectActivity(ActivityComponent component) { @@ -139,7 +140,6 @@ public class GroupActivity extends MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.group_actions, menu); - writeMenuItem = menu.findItem(R.id.action_group_compose_message); revealMenuItem = menu.findItem(R.id.action_group_reveal); inviteMenuItem = menu.findItem(R.id.action_group_invite); leaveMenuItem = menu.findItem(R.id.action_group_leave); @@ -152,9 +152,6 @@ public class GroupActivity extends @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { - case R.id.action_group_compose_message: - showTextInput(null); - return true; case R.id.action_group_member_list: Intent i1 = new Intent(this, GroupMemberListActivity.class); i1.putExtra(GROUP_ID, groupId.getBytes()); @@ -205,7 +202,6 @@ public class GroupActivity extends private void setGroupEnabled(boolean enabled) { isDissolved = !enabled; - if (writeMenuItem != null) writeMenuItem.setVisible(enabled); textInput.setSendButtonEnabled(enabled); list.getRecyclerView().setAlpha(enabled ? 1f : 0.5f); @@ -213,6 +209,8 @@ public class GroupActivity extends textInput.setVisibility(GONE); if (textInput.isKeyboardOpen()) textInput.hideSoftKeyboard(); if (textInput.isEmojiDrawerOpen()) textInput.hideEmojiDrawer(); + } else { + textInput.setVisibility(VISIBLE); } } @@ -229,7 +227,6 @@ public class GroupActivity extends leaveMenuItem.setVisible(true); dissolveMenuItem.setVisible(false); } - writeMenuItem.setVisible(!isDissolved); } private void showLeaveGroupDialog() { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java index 0c75305591d4220540a76c85683760b273b31d76..db6029e57c002ad2f8365ee7cc915670b4e7c386 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java @@ -17,6 +17,7 @@ import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import org.briarproject.briar.android.privategroup.conversation.GroupController.GroupListener; import org.briarproject.briar.android.threaded.ThreadListControllerImpl; import org.briarproject.briar.api.android.AndroidNotificationManager; +import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.privategroup.GroupMember; import org.briarproject.briar.api.privategroup.GroupMessage; @@ -60,9 +61,10 @@ class GroupControllerImpl extends @CryptoExecutor Executor cryptoExecutor, PrivateGroupManager privateGroupManager, GroupMessageFactory groupMessageFactory, EventBus eventBus, - Clock clock, AndroidNotificationManager notificationManager) { + MessageTracker messageTracker, Clock clock, + AndroidNotificationManager notificationManager) { super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor, - eventBus, clock, notificationManager); + eventBus, clock, notificationManager, messageTracker); this.privateGroupManager = privateGroupManager; this.groupMessageFactory = groupMessageFactory; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupMessageItem.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupMessageItem.java index a64769fdff867379df3bc6ff08917eb4fddbcc74..408fd29ba83429e35cf584f9e1df209a2f388398 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupMessageItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupMessageItem.java @@ -1,7 +1,6 @@ package org.briarproject.briar.android.privategroup.conversation; import android.support.annotation.LayoutRes; -import android.support.annotation.Nullable; import android.support.annotation.UiThread; import org.briarproject.bramble.api.identity.Author; @@ -12,6 +11,7 @@ import org.briarproject.briar.R; import org.briarproject.briar.android.threaded.ThreadItem; import org.briarproject.briar.api.privategroup.GroupMessageHeader; +import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; @UiThread diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupActivity.java index 5e7a64f56432a42a93ac4d611f0f16e558e472a6..30e80f8298a4ea6012b5e1e1470720729af0469d 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupActivity.java @@ -2,7 +2,6 @@ package org.briarproject.briar.android.privategroup.creation; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; @@ -14,6 +13,8 @@ import org.briarproject.briar.android.controller.handler.UiResultExceptionHandle import org.briarproject.briar.android.privategroup.conversation.GroupActivity; import org.briarproject.briar.android.sharing.BaseMessageFragment.MessageFragmentListener; +import javax.annotation.Nullable; + @MethodsNotNullByDefault @ParametersNotNullByDefault public class CreateGroupActivity extends BaseGroupInviteActivity implements diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupFragment.java index d0adfef241e3c3cc04057753003410b9f134409e..afede5594b79d0a9336bee889109a869ba258e92 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupFragment.java @@ -10,6 +10,7 @@ import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; +import org.briarproject.bramble.util.StringUtils; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.fragment.BaseFragment; @@ -84,9 +85,9 @@ public class CreateGroupFragment extends BaseFragment { private void validateName() { String name = this.name.getText().toString(); - if (name.length() < 1 || name.length() > MAX_GROUP_NAME_LENGTH) + if (name.length() < 1 || StringUtils.utf8IsTooLong(name, MAX_GROUP_NAME_LENGTH)) button.setEnabled(false); - else if(!button.isEnabled()) + else if (!button.isEnabled()) button.setEnabled(true); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItem.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItem.java index 11235ddbebb4253ce3e2255a7af5ca17f7a9d1ce..e916080bf272e85031a441b3a182051021e7dfdb 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/memberlist/MemberListItem.java @@ -1,7 +1,5 @@ package org.briarproject.briar.android.privategroup.memberlist; -import android.support.annotation.Nullable; - import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author.Status; @@ -9,6 +7,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.api.privategroup.GroupMember; import org.briarproject.briar.api.privategroup.Visibility; +import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; @NotThreadSafe diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportPrimer.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportPrimer.java index db44f92be319f41f2adad24209995096820d2d46..af709e937f23d44d4e28ff4a9975eef33141ec4f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportPrimer.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportPrimer.java @@ -146,7 +146,7 @@ public class BriarReportPrimer implements ReportPrimer { NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI); boolean wifiAvailable = wifi != null && wifi.isAvailable(); // Is wifi enabled? - o = ctx.getSystemService(WIFI_SERVICE); + o = ctx.getApplicationContext().getSystemService(WIFI_SERVICE); WifiManager wm = (WifiManager) o; boolean wifiEnabled = wm != null && wm.getWifiState() == WIFI_STATE_ENABLED; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/SharingStatusActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/SharingStatusActivity.java index 4fd258d45394cbb25061449127c3da03238cc13b..b07895d93965ee7d8c03754b0e5edbcb74bfbc5c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/SharingStatusActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/SharingStatusActivity.java @@ -2,7 +2,6 @@ package org.briarproject.briar.android.sharing; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.v7.widget.LinearLayoutManager; import android.view.MenuItem; @@ -25,6 +24,7 @@ import java.util.Collection; import java.util.List; import java.util.logging.Logger; +import javax.annotation.Nullable; import javax.inject.Inject; import static java.util.logging.Level.WARNING; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java index 21c2e0ede23e1f35689df3a9d6e837d48c87e975..0fbf26f806e3a46a1539a9b734c0e5c6c8d3acf7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java @@ -30,8 +30,8 @@ public class SplashScreenActivity extends BaseActivity { private static final Logger LOG = Logger.getLogger(SplashScreenActivity.class.getName()); - // This build expires on 1 May 2017 - private static final long EXPIRY_DATE = 1493593200 * 1000L; + // This build expires on 1 June 2017 + private static final long EXPIRY_DATE = 1496271600 * 1000L; @Inject protected ConfigController configController; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java index 72b03a03fc133340218e0f45ddb801446c9349db..21d0ede14a0ef78d8dcf269331406ef72fa335bf 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java @@ -1,6 +1,6 @@ package org.briarproject.briar.android.threaded; -import android.support.annotation.Nullable; +import android.os.Handler; import android.support.annotation.UiThread; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -14,6 +14,8 @@ import org.briarproject.briar.android.util.VersionedAdapter; import java.util.Collection; +import javax.annotation.Nullable; + import static android.support.v7.widget.RecyclerView.NO_POSITION; @UiThread @@ -26,6 +28,7 @@ public class ThreadItemAdapter<I extends ThreadItem> protected final NestedTreeList<I> items = new NestedTreeList<>(); private final ThreadItemListener<I> listener; private final LinearLayoutManager layoutManager; + private final Handler handler = new Handler(); private volatile int revision = 0; @@ -64,6 +67,17 @@ public class ThreadItemAdapter<I extends ThreadItem> revision++; } + void setItemWithIdVisible(MessageId messageId) { + int pos = 0; + for (I item : items) { + if (item.getId().equals(messageId)) { + layoutManager.scrollToPosition(pos); + break; + } + pos++; + } + } + public void setItems(Collection<I> items) { this.items.clear(); this.items.addAll(items); @@ -144,7 +158,7 @@ public class ThreadItemAdapter<I extends ThreadItem> /** * Returns the position of the first unread item below the current viewport */ - public int getVisibleUnreadPosBottom() { + int getVisibleUnreadPosBottom() { final int positionBottom = layoutManager.findLastVisibleItemPosition(); if (positionBottom == NO_POSITION) return NO_POSITION; for (int i = positionBottom + 1; i < items.size(); i++) { @@ -156,7 +170,7 @@ public class ThreadItemAdapter<I extends ThreadItem> /** * Returns the position of the first unread item above the current viewport */ - public int getVisibleUnreadPosTop() { + int getVisibleUnreadPosTop() { final int positionTop = layoutManager.findFirstVisibleItemPosition(); int position = NO_POSITION; for (int i = 0; i < items.size(); i++) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemList.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemList.java new file mode 100644 index 0000000000000000000000000000000000000000..f517e8e9ccb5c359c3864afe3f05a26dba75cc7f --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemList.java @@ -0,0 +1,15 @@ +package org.briarproject.briar.android.threaded; + +import org.briarproject.bramble.api.sync.MessageId; + +import java.util.List; + +import javax.annotation.Nullable; + +public interface ThreadItemList<I extends ThreadItem> extends List<I> { + + @Nullable + MessageId getFirstVisibleItemId(); + + void setFirstVisibleId(@Nullable MessageId bottomVisibleItemId); +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemListImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemListImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..2886607edce8eecc24a62075dfe07b385e21b94b --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemListImpl.java @@ -0,0 +1,22 @@ +package org.briarproject.briar.android.threaded; + +import org.briarproject.bramble.api.sync.MessageId; + +import java.util.ArrayList; + +import javax.annotation.Nullable; + +public class ThreadItemListImpl<I extends ThreadItem> extends ArrayList<I> + implements ThreadItemList<I> { + + private MessageId bottomVisibleItemId; + + @Override + public MessageId getFirstVisibleItemId() { + return bottomVisibleItemId; + } + + public void setFirstVisibleId(@Nullable MessageId bottomVisibleItemId) { + this.bottomVisibleItemId = bottomVisibleItemId; + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java index 77ef469716954ba513617fa19bc9fb9d0a75e128..891615e02660e6ec26099ac243f371b1d5e6c989 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java @@ -3,7 +3,6 @@ package org.briarproject.briar.android.threaded; import android.content.Intent; import android.os.Bundle; import android.support.annotation.CallSuper; -import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.annotation.UiThread; import android.support.design.widget.Snackbar; @@ -26,6 +25,7 @@ import org.briarproject.briar.android.controller.SharingController; import org.briarproject.briar.android.controller.SharingController.SharingListener; import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler; import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener; +import org.briarproject.briar.android.threaded.ThreadListController.ThreadListDataSource; import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener; import org.briarproject.briar.android.view.BriarRecyclerView; import org.briarproject.briar.android.view.TextInputView; @@ -38,13 +38,12 @@ import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout; import java.util.Collection; import java.util.logging.Logger; +import javax.annotation.Nullable; import javax.inject.Inject; import static android.support.design.widget.Snackbar.make; import static android.support.v7.widget.RecyclerView.NO_POSITION; import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE; -import static android.view.View.GONE; -import static android.view.View.VISIBLE; import static java.util.logging.Level.INFO; import static org.briarproject.briar.android.threaded.ThreadItemAdapter.UnreadCount; @@ -53,9 +52,8 @@ import static org.briarproject.briar.android.threaded.ThreadItemAdapter.UnreadCo public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadItemAdapter<I>, I extends ThreadItem, H extends PostHeader> extends BriarActivity implements ThreadListListener<H>, TextInputListener, SharingListener, - ThreadItemListener<I> { + ThreadItemListener<I>, ThreadListDataSource { - protected static final String KEY_INPUT_VISIBILITY = "inputVisibility"; protected static final String KEY_REPLY_ID = "replyId"; private static final Logger LOG = @@ -71,6 +69,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI private MessageId replyId; protected abstract ThreadListController<G, I, H> getController(); + @Inject protected SharingController sharingController; @@ -89,7 +88,6 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI getController().setGroupId(groupId); textInput = (TextInputView) findViewById(R.id.text_input_container); - textInput.setVisibility(GONE); textInput.setListener(this); list = (BriarRecyclerView) findViewById(R.id.list); layoutManager = new LinearLayoutManager(this); @@ -108,6 +106,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI updateUnreadCount(); } } + @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { @@ -148,6 +147,18 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI loadSharingContacts(); } + @Override + @Nullable + public MessageId getFirstVisibleMessageId() { + if (layoutManager != null && adapter != null) { + int position = + layoutManager.findFirstVisibleItemPosition(); + I i = adapter.getItemAt(position); + return i == null ? null : i.getId(); + } + return null; + } + protected abstract A createAdapter(LinearLayoutManager layoutManager); protected void loadNamedGroup() { @@ -171,18 +182,17 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI protected void loadItems() { final int revision = adapter.getRevision(); getController().loadItems( - new UiResultExceptionHandler<Collection<I>, DbException>(this) { + new UiResultExceptionHandler<ThreadItemList<I>, DbException>( + this) { @Override - public void onResultUi(Collection<I> items) { + public void onResultUi(ThreadItemList<I> items) { if (revision == adapter.getRevision()) { adapter.incrementRevision(); if (items.isEmpty()) { list.showData(); } else { - adapter.setItems(items); - list.showData(); - if (replyId != null) - adapter.setHighlightedItem(replyId); + initList(items); + updateTextInput(replyId); } } else { LOG.info("Concurrent update, reloading"); @@ -197,6 +207,15 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI }); } + private void initList(final ThreadItemList<I> items) { + adapter.setItems(items); + MessageId messageId = items.getFirstVisibleItemId(); + if (messageId != null) + adapter.setItemWithIdVisible(messageId); + updateUnreadCount(); + list.showData(); + } + protected void loadSharingContacts() { getController().loadSharingContacts( new UiResultExceptionHandler<Collection<ContactId>, DbException>( @@ -231,18 +250,9 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI list.stopPeriodicUpdate(); } - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - boolean visible = savedInstanceState.getBoolean(KEY_INPUT_VISIBILITY); - textInput.setVisibility(visible ? VISIBLE : GONE); - } - @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - boolean visible = textInput.getVisibility() == VISIBLE; - outState.putBoolean(KEY_INPUT_VISIBILITY, visible); ThreadItem replyItem = adapter.getHighlightedItem(); if (replyItem != null) { outState.putByteArray(KEY_REPLY_ID, replyItem.getId().getBytes()); @@ -262,9 +272,8 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI @Override public void onBackPressed() { - if (textInput.getVisibility() == VISIBLE) { - textInput.setVisibility(GONE); - adapter.setHighlightedItem(null); + if (adapter.getHighlightedItem() != null) { + updateTextInput(null); } else { super.onBackPressed(); } @@ -280,7 +289,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI @Override public void onReplyClick(final I item) { - showTextInput(item); + updateTextInput(item.getId()); if (textInput.isKeyboardOpen()) { scrollToItemAtTop(item); } else { @@ -330,20 +339,15 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI snackbar.show(); } - protected void showTextInput(@Nullable I replyItem) { - // An animation here would be an overkill because of the keyboard - // popping up. - // only clear the text when the input container was not visible - if (textInput.getVisibility() != VISIBLE) { - textInput.setVisibility(VISIBLE); - textInput.setText(""); + private void updateTextInput(@Nullable MessageId replyItemId) { + if (replyItemId != null) { + textInput.setHint(R.string.forum_message_reply_hint); + textInput.requestFocus(); + textInput.showSoftKeyboard(); + } else { + textInput.setHint(R.string.forum_new_message_hint); } - textInput.requestFocus(); - textInput.showSoftKeyboard(); - textInput.setHint(replyItem == null ? R.string.forum_new_message_hint : - R.string.forum_message_reply_hint); - adapter.setHighlightedItem( - replyItem == null ? null : replyItem.getId()); + adapter.setHighlightedItem(replyItemId); } @Override @@ -369,9 +373,8 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI }; getController().createAndStoreMessage(text, replyItem, handler); textInput.hideSoftKeyboard(); - textInput.setVisibility(GONE); textInput.setText(""); - adapter.setHighlightedItem(null); + updateTextInput(null); } protected abstract int getMaxBodyLength(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java index caebd1ec65d53dad3c590e0d1cf287703073e0d2..d39c8b453a6c1c5852d9c56663edd1d7ca0fe4fa 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java @@ -6,6 +6,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.android.DestroyableContext; import org.briarproject.briar.android.controller.ActivityLifecycleController; import org.briarproject.briar.android.controller.handler.ExceptionHandler; @@ -30,7 +31,7 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem void loadItem(H header, ResultExceptionHandler<I, DbException> handler); - void loadItems(ResultExceptionHandler<Collection<I>, DbException> handler); + void loadItems(ResultExceptionHandler<ThreadItemList<I>, DbException> handler); void markItemRead(I item); @@ -41,7 +42,7 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem void deleteNamedGroup(ExceptionHandler<DbException> handler); - interface ThreadListListener<H> extends DestroyableContext { + interface ThreadListListener<H> extends ThreadListDataSource { @UiThread void onHeaderReceived(H header); @@ -52,4 +53,10 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem void onInvitationAccepted(ContactId c); } + interface ThreadListDataSource extends DestroyableContext { + + @UiThread @Nullable + MessageId getFirstVisibleMessageId(); + } + } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java index a2db5242d9cd8bba435fa1cd50bf28d0e79e8a5e..0793d785adf6ec8744748cf8df28175da1df766a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java @@ -22,14 +22,13 @@ import org.briarproject.briar.android.controller.handler.ExceptionHandler; import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener; import org.briarproject.briar.api.android.AndroidNotificationManager; +import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.NamedGroup; import org.briarproject.briar.api.client.PostHeader; import org.briarproject.briar.api.client.ThreadedMessage; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; @@ -55,18 +54,21 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T protected final AndroidNotificationManager notificationManager; protected final Executor cryptoExecutor; protected final Clock clock; + private final MessageTracker messageTracker; protected volatile L listener; protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor, LifecycleManager lifecycleManager, IdentityManager identityManager, @CryptoExecutor Executor cryptoExecutor, EventBus eventBus, - Clock clock, AndroidNotificationManager notificationManager) { + Clock clock, AndroidNotificationManager notificationManager, + MessageTracker messageTracker) { super(dbExecutor, lifecycleManager); this.identityManager = identityManager; this.cryptoExecutor = cryptoExecutor; this.notificationManager = notificationManager; this.clock = clock; this.eventBus = eventBus; + this.messageTracker = messageTracker; } @Override @@ -97,6 +99,19 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T @Override public void onActivityDestroy() { + dbExecutor.execute(new Runnable() { + @Override + public void run() { + try { + messageTracker + .storeMessageId(groupId, + listener.getFirstVisibleMessageId()); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } + } + }); } @CallSuper @@ -144,7 +159,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T @Override public void loadItems( - final ResultExceptionHandler<Collection<I>, DbException> handler) { + final ResultExceptionHandler<ThreadItemList<I>, DbException> handler) { checkGroupId(); runOnDbThread(new Runnable() { @Override @@ -293,11 +308,16 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T @DatabaseExecutor protected abstract void deleteNamedGroup(G groupItem) throws DbException; - private List<I> buildItems(Collection<H> headers) { - List<I> items = new ArrayList<>(); + private ThreadItemList<I> buildItems(Collection<H> headers) + throws DbException { + ThreadItemList<I> items = new ThreadItemListImpl<>(); for (H h : headers) { items.add(buildItem(h, bodyCache.get(h.getId()))); } + MessageId msgId = messageTracker.loadStoredMessageId(groupId); + if (LOG.isLoggable(INFO)) + LOG.info("Loaded last top visible message id " + msgId); + items.setFirstVisibleId(msgId); return items; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java index 703747495f544ce43c3b071d60d97814dd9ebaab..6dc2920ed0a2cec28cb72411b7ba32dce2bbfb25 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java @@ -1,7 +1,6 @@ package org.briarproject.briar.android.util; import android.content.Context; -import android.support.annotation.Nullable; import android.support.design.widget.TextInputLayout; import android.support.v4.app.FragmentManager; import android.support.v4.content.ContextCompat; @@ -23,6 +22,8 @@ import org.briarproject.briar.R; import org.briarproject.briar.android.view.ArticleMovementMethod; import org.briarproject.briar.android.widget.LinkDialogFragment; +import javax.annotation.Nullable; + import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH; import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java b/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java index e7f4fa92f5387377a72ea82ba02f7b0d1b3ae9bf..0270cfea34d2353b1fdcb90b7c8d670883ad0471 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java @@ -2,7 +2,6 @@ package org.briarproject.briar.android.view; import android.content.Context; import android.content.res.TypedArray; -import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.design.widget.FloatingActionButton; import android.util.AttributeSet; @@ -13,6 +12,8 @@ import android.widget.TextView; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.R; +import javax.annotation.Nullable; + @UiThread @NotNullByDefault public class UnreadMessageButton extends FrameLayout { @@ -36,8 +37,7 @@ public class UnreadMessageButton extends FrameLayout { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater - .inflate(R.layout.unread_message_button, this, true); + inflater.inflate(R.layout.unread_message_button, this, true); fab = (FloatingActionButton) findViewById(R.id.fab); unread = (TextView) findViewById(R.id.unreadCountView); @@ -64,15 +64,11 @@ public class UnreadMessageButton extends FrameLayout { public void setUnreadCount(int count) { if (count == 0) { - fab.setVisibility(GONE); -// fab.hide(); - unread.setVisibility(GONE); + setVisibility(INVISIBLE); } else { // FIXME: Use animations when upgrading to support library 24.2.0 // https://code.google.com/p/android/issues/detail?id=216469 - fab.setVisibility(VISIBLE); -// if (!fab.isShown()) fab.show(); - unread.setVisibility(VISIBLE); + setVisibility(VISIBLE); unread.setText(String.valueOf(count)); } } diff --git a/briar-android/src/main/res/drawable/chevron48dp_down.xml b/briar-android/src/main/res/drawable/chevron48dp_down.xml deleted file mode 100644 index 6f1f305dfaffc9ce196424027ea46f25e94be90a..0000000000000000000000000000000000000000 --- a/briar-android/src/main/res/drawable/chevron48dp_down.xml +++ /dev/null @@ -1,9 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportHeight="48.0" - android:viewportWidth="48.0"> - <path - android:fillColor="#06b9ff" - android:pathData="M9.1,19.3l14.9,11.8l14.9,-11.8l-1.9,-2.4l-13,10.4l-13,-10.4z"/> -</vector> diff --git a/briar-android/src/main/res/drawable/chevron48dp_up.xml b/briar-android/src/main/res/drawable/chevron48dp_up.xml deleted file mode 100644 index 50894206ec5cbe88abf1f75335330eabb179184e..0000000000000000000000000000000000000000 --- a/briar-android/src/main/res/drawable/chevron48dp_up.xml +++ /dev/null @@ -1,9 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportHeight="48.0" - android:viewportWidth="48.0"> - <path - android:fillColor="#06b9ff" - android:pathData="M38.9,28.7l-14.9,-11.8l-14.9,11.8l1.9,2.4l13,-10.4l13,10.4z"/> -</vector> diff --git a/briar-android/src/main/res/drawable/ic_rss_feed.xml b/briar-android/src/main/res/drawable/ic_rss_feed.xml index 6d441fa064cd0a237076a0142d60f145059e0623..167b7d7b976c976cc09053e3a130164f85a8acec 100644 --- a/briar-android/src/main/res/drawable/ic_rss_feed.xml +++ b/briar-android/src/main/res/drawable/ic_rss_feed.xml @@ -7,7 +7,7 @@ <path android:fillColor="#ffa500" - android:pathData="M0,8.88178e-16 L30,8.88178e-16 L30,30 L0,30 L0,8.88178e-16 Z"/> + android:pathData="M0,0 L30,0 L30,30 L0,30 L0,0 Z"/> <path android:fillColor="#ffffff" android:pathData="M8.9322,18.0339 C10.6078,18.0339,11.9661,19.3922,11.9661,21.0678 diff --git a/briar-android/src/main/res/drawable/level_indicator_circle.xml b/briar-android/src/main/res/drawable/level_indicator_circle.xml index 22fc407d3a46ed4d87b0f83431e84f6782e7ef1f..265ff997f90f11bdb0dd027d6572195d90a65cd7 100644 --- a/briar-android/src/main/res/drawable/level_indicator_circle.xml +++ b/briar-android/src/main/res/drawable/level_indicator_circle.xml @@ -5,5 +5,5 @@ <stroke android:width="2dp" - android:color="@color/forum_discussion_nested_line"/> + android:color="@color/thread_indicator"/> </shape> \ No newline at end of file diff --git a/briar-android/src/main/res/drawable/selector_chevron.xml b/briar-android/src/main/res/drawable/selector_chevron.xml deleted file mode 100644 index f3a72a87dd62e3bcfec63aef1c5c966165f6a810..0000000000000000000000000000000000000000 --- a/briar-android/src/main/res/drawable/selector_chevron.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:drawable="@drawable/chevron48dp_down" android:state_selected="true"/> - <item android:drawable="@drawable/chevron48dp_up"/> -</selector> \ No newline at end of file diff --git a/briar-android/src/main/res/drawable/splash_screen.xml b/briar-android/src/main/res/drawable/splash_screen.xml index 25b898dee662036ef53d84e5746d56bc1bdfc128..a8c8a1c36e2ff25c12ec56ec3ca999affdc35205 100644 --- a/briar-android/src/main/res/drawable/splash_screen.xml +++ b/briar-android/src/main/res/drawable/splash_screen.xml @@ -12,9 +12,9 @@ android:fillColor="#87c214" android:pathData="M64.9004,0 C55.2004,0,47.1992,7.99922,47.1992,17.6992 L47.1992,40.1992 L90.8008,40.1992 L90.8008,17.6992 -C90.8008,7.99922,82.8992,-4.73695e-15,73.1992,0 L64.9004,0 Z M161.9,0 +C90.8008,7.99922,82.8992,0,73.1992,0 L64.9004,0 Z M161.9,0 C152.2,0,144.199,7.99922,144.199,17.6992 L144.199,137.199 L187.801,137.199 -L187.801,17.6992 C187.801,7.99922,179.899,-4.73695e-15,170.199,0 L161.9,0 Z +L187.801,17.6992 C187.801,7.99922,179.899,0,170.199,0 L161.9,0 Z M47.1992,97.8008 L47.1992,217.301 C47.1992,227.001,55.1004,235,64.9004,235 L73.1992,235 C82.8992,235,90.9004,227.001,90.9004,217.301 L90.9004,97.8008 L47.1992,97.8008 Z M144.199,194.801 L144.199,217.301 @@ -25,12 +25,12 @@ C179.899,235,187.9,227.001,187.9,217.301 L187.9,194.801 L144.199,194.801 Z"/> android:pathData="M144.2,144.2 L187.9,144.2 L187.9,187.9 L144.2,187.9 L144.2,144.2 Z"/> <path android:fillColor="#95d220" - android:pathData="M17.6992,47.1992 C7.99922,47.1992,2.36848e-15,55.1004,0,64.9004 L0,73.1992 + android:pathData="M17.6992,47.1992 C7.99922,47.1992,0,55.1004,0,64.9004 L0,73.1992 C0,82.8992,7.89922,90.9004,17.6992,90.9004 L137.199,90.9004 L137.199,47.1992 L17.6992,47.1992 Z M194.801,47.1992 L194.801,90.9004 L217.301,90.9004 C227.001,90.9004,235,82.9992,235,73.1992 L235,64.9004 C235,55.1004,227.001,47.1992,217.301,47.1992 L194.801,47.1992 Z M17.6992,144.199 -C7.99922,144.199,2.36848e-15,152.1,0,161.9 L0,170.199 +C7.99922,144.199,0,152.1,0,161.9 L0,170.199 C0,179.899,7.89922,187.9,17.6992,187.9 L40.1992,187.9 L40.1992,144.199 L17.6992,144.199 Z M97.8008,144.199 L97.8008,187.9 L217.301,187.9 C227.001,187.9,235,179.899,235,170.199 L235,161.9 diff --git a/briar-android/src/main/res/menu/forum_actions.xml b/briar-android/src/main/res/menu/forum_actions.xml index cd4e4573c50e29dddeb025f5c7980800665ca4bb..349f70582997f4fe43a697b0af7f620fbfcf5f50 100644 --- a/briar-android/src/main/res/menu/forum_actions.xml +++ b/briar-android/src/main/res/menu/forum_actions.xml @@ -3,12 +3,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> - <item - android:id="@+id/action_forum_compose_post" - android:icon="@drawable/forum_item_create_white" - android:title="@string/forum_compose_post" - app:showAsAction="always"/> - <item android:id="@+id/action_forum_share" android:icon="@drawable/social_share_white" diff --git a/briar-android/src/main/res/menu/group_actions.xml b/briar-android/src/main/res/menu/group_actions.xml index a67e7329981f2ca1a5a30ce0faa8e31689da14a6..2f4315a75220103e7fc590f3b112213753f50dea 100644 --- a/briar-android/src/main/res/menu/group_actions.xml +++ b/briar-android/src/main/res/menu/group_actions.xml @@ -3,12 +3,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> - <item - android:id="@+id/action_group_compose_message" - android:icon="@drawable/forum_item_create_white" - android:title="@string/groups_compose_message" - app:showAsAction="always"/> - <item android:id="@+id/action_group_member_list" android:icon="@drawable/ic_group_white" diff --git a/briar-android/src/main/res/values-de/strings.xml b/briar-android/src/main/res/values-de/strings.xml index 012242b2557666732003b4aabe938888f37f855c..9677259945897dd12d31ea29f1df43fbf658ee66 100644 --- a/briar-android/src/main/res/values-de/strings.xml +++ b/briar-android/src/main/res/values-de/strings.xml @@ -151,7 +151,6 @@ <string name="groups_create_group_invitation_button">Einladung schicken</string> <string name="groups_create_group_hint">Gebe Deiner privaten Gruppe einen Namen</string> <string name="groups_invitation_sent">Gruppeneinladung versendet</string> - <string name="groups_compose_message">Nachricht erstellen</string> <string name="groups_message_sent">Nachricht gesendet</string> <string name="groups_member_list">Mitglieder</string> <string name="groups_invite_members">Mitglieder einladen</string> @@ -174,14 +173,22 @@ <string name="groups_invitations_invitation_received">%1$s hat dich eingeladen der Gruppe \"%2$s\" beizutreten.</string> <string name="groups_invitations_joined">Gruppe beigetreten</string> <string name="groups_invitations_declined">Gruppeneinladung abgelehnt</string> + <plurals name="groups_invitations_open"> + <item quantity="one">%d offene Gruppeneinladung</item> + <item quantity="other">%d offene Gruppeneinladungen</item> + </plurals> <string name="groups_invitations_response_accepted_sent">Gruppeneinladung von %s angenommen.</string> <string name="groups_invitations_response_declined_sent">Gruppeneinladung von %s abgelehnt.</string> <string name="groups_invitations_response_accepted_received">%s hat die Einladung zur Gruppe angenommen.</string> <string name="groups_invitations_response_declined_received">%s hat die Einladung zur Gruppe abgelehnt.</string> + <string name="sharing_status_groups">Nur der Ersteller kann neue Mitglieder zu einer Gruppe einladen. HIer alle aktuellen Mitglieder dieser Gruppe.</string> <!--Private Groups Revealing Contacts--> <string name="groups_reveal_contacts">Kontakte teilen</string> <string name="groups_reveal_dialog_message">Kontakte können mit allen derzeitigen und zukünftigen Mitgliedern dieser Gruppe geteilt werden.\n\nDas beschleunigt die Verbindung zu der Gruppe und macht sie zusätzlich zuverlässiger, da Kommunikation mit den Mitgliedern auch dann erfolgen kann, wenn der Ersteller der Gruppe offline ist.</string> <string name="groups_reveal_visible">Verbindung zum Kontakt ist für die Gruppe sichtbar</string> + <string name="groups_reveal_visible_revealed_by_us">Beziehung zum Kontakt ist für diese Gruppe sichtbar (selbst offengelegt)</string> + <string name="groups_reveal_visible_revealed_by_contact">Beziehung zum Kontakt ist für diese Gruppe sichtbar (offengelegt durch %s)</string> + <string name="groups_reveal_invisible">Beziehung zum Kontakt ist für diese Gruppe nicht sichtbar</string> <!--Forums--> <string name="no_forums">Du hast noch keine Foren.\n\nWarum erstellst du nicht einfach selbst ein neues Forum, indem du auf das \"+\"-Icon am oberen Bildschirmrand tippst?\n\nDu kannst auch deine Kontakte auffordern, Foren mit dir zu teilen.</string> <string name="create_forum_title">Neues Forum</string> @@ -194,15 +201,10 @@ <item quantity="one">%d Beitrag</item> <item quantity="other">%d Beiträge</item> </plurals> - <string name="forum_compose_post">Neuer Forenbeitrag</string> <string name="forum_new_entry_posted">Forenbeitrag wurde veröffentlicht.</string> <string name="forum_new_message_hint">Neuer Eintrag</string> <string name="forum_message_reply_hint">Neue Antwort</string> <string name="btn_reply">Antworten</string> - <plurals name="message_replies"> - <item quantity="one">%1$d Antwort</item> - <item quantity="other">%1$d Antworten</item> - </plurals> <string name="forum_leave">Forum verlassen</string> <string name="dialog_title_leave_forum">Verlassen des Forums bestätigen</string> <string name="dialog_message_leave_forum">Bist du sicher, dass du dieses Forum verlassen willst? Kontakte, die du mit diesem Forum geteilt hast, werden keine Updates von diesem Forum mehr bekommen.</string> @@ -229,6 +231,8 @@ <string name="forum_invitation_response_accepted_received">%s hat die Forumeinladung akzeptiert.</string> <string name="forum_invitation_response_declined_received">%s hat die Forumseinladung abgelehnt.</string> <string name="sharing_status">Sharing Status</string> + <string name="sharing_status_forum">Jedes Mitglied eines Forums kann dieses mit seinen Kontakten teilen. Du teilst dieses Forum mit den folgenden Kontakten. Möglicherweise gibt es Mitglieder die nicht sichtbar sind.</string> + <string name="shared_with">Geteilt mit %1$d (%2$d online)</string> <plurals name="forums_shared"> <item quantity="one">%d Forum von Kontaken geteilt</item> <item quantity="other">%d Foren von Kontakten geteilt</item> @@ -265,6 +269,7 @@ <string name="blogs_sharing_invitations_title">Blogeinladungen</string> <string name="blogs_sharing_joined_toast">Blog abonniert</string> <string name="blogs_sharing_declined_toast">Blogeinladung abgelehnt</string> + <string name="sharing_status_blog">Jeder Abonnent eines Blogs kann diesen mit seinen Kontakten teilen. Du teilst diesen Blog mit den folgenden Kontakten. Möglicherweise gibt es Abonnenten die nicht sichtbar sind.</string> <!--RSS Feeds--> <string name="blogs_rss_feeds_import">RSS-Feed importieren</string> <string name="blogs_rss_feeds_import_button">Importieren</string> @@ -274,6 +279,9 @@ <string name="blogs_rss_feeds_manage_imported">Importiert:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_updated">Letzte Aktualisierung:</string> + <string name="blogs_rss_remove_feed">Feed entfernen</string> + <string name="blogs_rss_remove_feed_dialog_message">Soll der Feed mit allen Posts wirklich gelöscht werden?\nGeteilte Posts werden dabei nicht von anderen Geräten gelöscht.</string> + <string name="blogs_rss_remove_feed_ok">Feed entfernen</string> <string name="blogs_rss_feeds_manage_delete_error">Der Feed konnte nicht gelöscht werden!</string> <string name="blogs_rss_feeds_manage_empty_state">Du hast bisher noch keine RSS Feeds importiert. Tippe auf das \"+\"-Icon am oberen Bildschirmrand um einen neuen Feed hinzuzufügen.</string> <string name="blogs_rss_feeds_manage_error">Es gab ein Problem beim Laden deiner Feeds. Bitte versuche es später erneut.</string> @@ -282,6 +290,10 @@ <string name="bluetooth_setting">Ãœber Bluetooth verbinden</string> <string name="bluetooth_setting_enabled">Sobald Kontakte in der Nähe sind</string> <string name="bluetooth_setting_disabled">Nur beim Hinzufügen von Kontakten</string> + <string name="tor_network_setting">Ãœber Tor verbinden</string> + <string name="tor_network_setting_never">Nie</string> + <string name="tor_network_setting_wifi">Nur WLAN</string> + <string name="tor_network_setting_always">WLAN oder mobile Datenverbindung</string> <!--Settings Security and Panic--> <string name="security_settings_title">Sicherheit</string> <string name="change_password">Passwort ändern</string> @@ -341,4 +353,9 @@ <string name="dev_report_saved">Der Bericht wurde gespeichert. Er wird verschickt, wenn Du Dich das nächste Mal bei Briar anmeldest.</string> <!--Sign Out--> <string name="progress_title_logout">Von Briar abmelden ...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Bildschirmfilter erkannt</string> + <string name="screen_filter_body">Diese Apps können andere Apps überlagern:\n\n%1$s \n\nBriar reagiert im Fall einer Ãœberlagerung nicht auf Benutzereingaben. +Falls dadurch Probleme in der Verwendung von Briar entstehen, versuche diese Apps zu deaktivieren.\n</string> + <string name="checkbox_dont_show_again">Nicht noch einmal für diese Apps warnen</string> </resources> diff --git a/briar-android/src/main/res/values-es/strings.xml b/briar-android/src/main/res/values-es/strings.xml index f4b7c982db549138630668ed87289bd1582e940a..bd49a3f6e5ab8990e8f9aa56cec33ca880b64cee 100644 --- a/briar-android/src/main/res/values-es/strings.xml +++ b/briar-android/src/main/res/values-es/strings.xml @@ -151,7 +151,6 @@ <string name="groups_create_group_invitation_button">Enviar invitación</string> <string name="groups_create_group_hint">Dar nombre al grupo privado</string> <string name="groups_invitation_sent">Se ha mandado la invitación de grupo</string> - <string name="groups_compose_message">Escribir mensaje</string> <string name="groups_message_sent">Mensaje enviado</string> <string name="groups_member_list">Integrantes</string> <string name="groups_invite_members">Invitar miembros</string> @@ -182,6 +181,7 @@ <string name="groups_invitations_response_declined_sent">Declinaste la invitación de grupo de %s.</string> <string name="groups_invitations_response_accepted_received">%s ha aceptado la invitación al grupo.</string> <string name="groups_invitations_response_declined_received">%s ha declinado la invitación al grupo.</string> + <string name="sharing_status_groups">Solo el creador puede invitar nuevos miembros al grupo. Abajo se listan todos los participantes actuales.</string> <!--Private Groups Revealing Contacts--> <string name="groups_reveal_contacts">Revelar contactos</string> <string name="groups_reveal_dialog_message">Puedes elegir si revelar los contactos a los actuales y futuros integrantes de este grupo.\n\nRevelar los contactos mejora la velocidad y la fiabilidad de tu conexión, porque puedes comunicarte con los contactos revelados incluso cuando el creador del grupo no se encuentra conectado.</string> @@ -201,15 +201,10 @@ <item quantity="one">%d publicación</item> <item quantity="other">%d publicaciones</item> </plurals> - <string name="forum_compose_post">Nueva publicación en el foro</string> <string name="forum_new_entry_posted">Entrada en el foro publicada</string> <string name="forum_new_message_hint">Nueva entrada</string> <string name="forum_message_reply_hint">Nueva respuesta</string> <string name="btn_reply">Responder</string> - <plurals name="message_replies"> - <item quantity="one">%1$d respuesta</item> - <item quantity="other">%1$d respuestas</item> - </plurals> <string name="forum_leave">Abandonar foro</string> <string name="dialog_title_leave_forum">Confirmación abandono del foro</string> <string name="dialog_message_leave_forum">¿Seguro que quieres abandonar el foro? Puede que los contactos que invitaste al foro dejen de recibir actualizaciones del mismo.</string> @@ -236,6 +231,7 @@ <string name="forum_invitation_response_accepted_received">%s aceptó la invitación al foro.</string> <string name="forum_invitation_response_declined_received">%s rechazó la invitación al foro.</string> <string name="sharing_status">Estado de la compartición</string> + <string name="sharing_status_forum">Cualquier miembro de un foro puede compartirlo con sus contactos. Estás compartiendo este foro con los contactos listados a continuación. Puede haber otros miembros que no puedes ver.</string> <string name="shared_with">Compartido con %1$d (%2$d en lÃnea)</string> <plurals name="forums_shared"> <item quantity="one">%d foro compartido por contactos</item> @@ -273,6 +269,7 @@ <string name="blogs_sharing_invitations_title">Invitaciones a blogs</string> <string name="blogs_sharing_joined_toast">Suscrito al blog</string> <string name="blogs_sharing_declined_toast">Rechazada invitación al blog</string> + <string name="sharing_status_blog">Cualquiera que se suscriba a un blog puede compartirlo con sus contactos. Estás compartiendo este blog con contactos listados a continuación. Puede haber otros suscriptores que no puedes ver.</string> <!--RSS Feeds--> <string name="blogs_rss_feeds_import">Importar canal RSS</string> <string name="blogs_rss_feeds_import_button">Importar</string> @@ -282,6 +279,9 @@ <string name="blogs_rss_feeds_manage_imported">Importado:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_updated">Última actualización:</string> + <string name="blogs_rss_remove_feed">Eliminar canal RSS</string> + <string name="blogs_rss_remove_feed_dialog_message">¿Seguro que quieres borrar este canal RSS y todas sus publicaciones?\nNo se eliminará ningún artÃculo que hayas compartido de los dispositivos de otras personas.</string> + <string name="blogs_rss_remove_feed_ok">Eliminar canal RSS</string> <string name="blogs_rss_feeds_manage_delete_error">¡El canal no pudo ser eliminado!</string> <string name="blogs_rss_feeds_manage_empty_state">No has importado ningún canal RSS.\n\n¿Por qué no pulsas el signo más de la esquina superior derecha para añadir el primero?</string> <string name="blogs_rss_feeds_manage_error">Hubo un problema cargando tus canales RSS. Por favor, prueba más tarde.</string> @@ -290,6 +290,10 @@ <string name="bluetooth_setting">Connectar mediante Bluetooth</string> <string name="bluetooth_setting_enabled">Cuando haya contactos cerca</string> <string name="bluetooth_setting_disabled">Solo al añadir contactos</string> + <string name="tor_network_setting">Conectar a través de Tor</string> + <string name="tor_network_setting_never">Nunca</string> + <string name="tor_network_setting_wifi">Solo con wifi</string> + <string name="tor_network_setting_always">Con wifi o datos móviles</string> <!--Settings Security and Panic--> <string name="security_settings_title">Seguridad</string> <string name="change_password">Cambiar contraseña</string> @@ -349,4 +353,9 @@ <string name="dev_report_saved">Informe guardado. Se enviará la próxima vez que inicies Briar.</string> <!--Sign Out--> <string name="progress_title_logout">Saliendo de Briar…</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Filtro de pantalla detectado</string> + <string name="screen_filter_body">Las siguientes aplicaciones pueden mostrarse por encima de otras:\n\n%1$s \n\nBriar no reaccionará a los toques mientras otra aplicación se muestre encima. +Si experiencia algún problema, pruebe a desactivar esas aplicaciones cuando use Briar.\n</string> + <string name="checkbox_dont_show_again">No mostrar más para estas aplicaciones</string> </resources> diff --git a/briar-android/src/main/res/values-fr/strings.xml b/briar-android/src/main/res/values-fr/strings.xml index 436149c56002f9fae8d0895a31b8e485dd1a71c0..4c91c4a6a613c37084112f38712d150dc56246a3 100644 --- a/briar-android/src/main/res/values-fr/strings.xml +++ b/briar-android/src/main/res/values-fr/strings.xml @@ -19,7 +19,7 @@ <string name="dialog_message_lost_password">Votre compte Briar est enregistré chiffré sur votre appareil et non sur le \"cloud\", par conséquent, votre mot de passe ne peut être réinitialisé. Voulez-vous supprimer votre compte et démarrer à nouveau ?\n\nAttention : vos identités, contacts et messages seront définitivement perdus.</string> <string name="startup_failed_notification_title">Briar n\'a pas pu démarrer</string> <string name="startup_failed_notification_text">Vous devrez peut-être réinstaller Briar.</string> - <string name="startup_failed_activity_title">Echec de démarrage de Briar.</string> + <string name="startup_failed_activity_title">Échec de démarrage de Briar</string> <string name="startup_failed_db_error">Pour une raison indéterminée, votre base de donnée Briar est corrompue et irrécupérable. Vos comptes, données et contacts sont perdus. Vous devez malheureusement réinstaller Briar et configurer un nouveau compte.</string> <string name="startup_failed_service_error">Briar n\'a pas pu démarrer un module nécessaire. Réinstaller Briar résout généralement ce problème. Veuillez noter que vous perdrez votre compte et toutes les données associées puisque Briar n\'utilise pas de serveurs centralisés pour enregistrer les données.</string> <string name="expiry_warning">Ce logiciel est arrivé à expiration.\nVeuillez installer une version plus récente.</string> @@ -151,7 +151,6 @@ <string name="groups_create_group_invitation_button">Envoyer invitation</string> <string name="groups_create_group_hint">Ajouter un nom au groupe privé</string> <string name="groups_invitation_sent">Invitation envoyée au groupe</string> - <string name="groups_compose_message">Composer message</string> <string name="groups_message_sent">Message envoyé</string> <string name="groups_member_list">Liste de participants</string> <string name="groups_invite_members">Inviter des participants</string> @@ -182,6 +181,7 @@ <string name="groups_invitations_response_declined_sent">Vous avez refusé l\'invitation du groupe de %s.</string> <string name="groups_invitations_response_accepted_received">%s a accepté l\'invitation du groupe.</string> <string name="groups_invitations_response_declined_received">%s a décliné l\'invitation du groupe.</string> + <string name="sharing_status_groups">Seul l\'initiateur du groupe peut inviter de nouveaux membres. Voici la liste des membres actuels.</string> <!--Private Groups Revealing Contacts--> <string name="groups_reveal_contacts">Dévoiler les contacts</string> <string name="groups_reveal_dialog_message">Vous pouvez choisir de dévoiler les contacts à tous les membres actuels et futurs de ce groupe.\n\nDévoiler les contacts vous assure une connexion au groupe plus rapide et plus fiable car vous pouvez communiquer avec les contacts dévoilés même si l\'initiateur du groupe est hors ligne.</string> @@ -201,15 +201,10 @@ <item quantity="one">%d message</item> <item quantity="other">%d messages</item> </plurals> - <string name="forum_compose_post">Nouveau post de forum</string> <string name="forum_new_entry_posted">Entrée de forum postée</string> <string name="forum_new_message_hint">Nouvelle entrée</string> <string name="forum_message_reply_hint">Nouvelle réponse</string> <string name="btn_reply">Répondre</string> - <plurals name="message_replies"> - <item quantity="one">%1$d réponse</item> - <item quantity="other">%1$d réponses</item> - </plurals> <string name="forum_leave">Quitter le forum</string> <string name="dialog_title_leave_forum">Confirmer la sortie du forum</string> <string name="dialog_message_leave_forum">Êtes-vous sûr de vouloir quitter ce forum ? Les contacts avec qui vous l\'avez partagé pourraient ne plus recevoir ses mises à jour.</string> @@ -236,6 +231,7 @@ <string name="forum_invitation_response_accepted_received">%s a accepté l\'invitation au forum.</string> <string name="forum_invitation_response_declined_received">%s a décliné l\'invitation au forum.</string> <string name="sharing_status">Etat de partage</string> + <string name="sharing_status_forum">Tous les participants d\'un forum peuvent le partager avec leurs contacts. Vous partagez ce forum avec les contacts suivants. Il y a peut-être d\'autres participants que vous ne pouvez voir.</string> <string name="shared_with">Partagé avec %1$d (%2$d en ligne)</string> <plurals name="forums_shared"> <item quantity="one">%d forum partagé par des contacts</item> @@ -273,6 +269,7 @@ <string name="blogs_sharing_invitations_title">Invitations au blog</string> <string name="blogs_sharing_joined_toast">Abonné au Blog</string> <string name="blogs_sharing_declined_toast">Invitation au blog refusée</string> + <string name="sharing_status_blog">Quiconque est abonné à un blog peut le partager avec ses contacts. Vous partagez ce blog avec les contacts suivants. Il y a peut-être d\'autres abonnés que vous ne pouvez voir.</string> <!--RSS Feeds--> <string name="blogs_rss_feeds_import">Import de flux RSS</string> <string name="blogs_rss_feeds_import_button">Importer</string> @@ -282,6 +279,9 @@ <string name="blogs_rss_feeds_manage_imported">Importé :</string> <string name="blogs_rss_feeds_manage_author">Auteur :</string> <string name="blogs_rss_feeds_manage_updated">Dernière mise à jour :</string> + <string name="blogs_rss_remove_feed">Supprimer le flux</string> + <string name="blogs_rss_remove_feed_dialog_message">Êtes-vous sûr de vouloir supprimer ce flux et tous ses messages ?\nLes postes que vous avez partagés ne seront pas supprimés des appareils des autres personnes.</string> + <string name="blogs_rss_remove_feed_ok">Supprimer le flux</string> <string name="blogs_rss_feeds_manage_delete_error">Le flux n\'a pas pu être supprimé !</string> <string name="blogs_rss_feeds_manage_empty_state">Vous n\'avez importé aucun flux RSS.\n\nPourquoi ne pas cliquer le plus dans le coin en haut à droite pour ajouter votre premier ?</string> <string name="blogs_rss_feeds_manage_error">Problème lors du chargement de vos flux. Réessayer ultérieurement.</string> @@ -353,4 +353,9 @@ <string name="dev_report_saved">Rapport enregistré. Il sera envoyé lors de votre prochaine connexion à Briar.</string> <!--Sign Out--> <string name="progress_title_logout">Déconnexion de Briar ...</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">Filtre d\'écran détecté</string> + <string name="screen_filter_body">Les applications suivantes ont l\'autorisation de s\'afficher par dessus d\'autres :\n\n%1$s \n\nBriar ne répondra pas aux touches lorsqu\'une autre application s\'affiche par dessus. +En cas de problèmes, essayer d\'arrêter ces applications durant l\'utilisation de Briar.\n</string> + <string name="checkbox_dont_show_again">Ne plus m\'avertir à propos de ces applications</string> </resources> diff --git a/briar-android/src/main/res/values-it/strings.xml b/briar-android/src/main/res/values-it/strings.xml index 0c136181c62370a01ae9e4ee9f0a49f2e6e12db4..b905d0ec7102c592d738c2f8494c2727d961d14a 100644 --- a/briar-android/src/main/res/values-it/strings.xml +++ b/briar-android/src/main/res/values-it/strings.xml @@ -124,7 +124,6 @@ <string name="groups_create_group_invitation_button">Invia invito</string> <string name="groups_create_group_hint">Inserisci un nome per il tuo gruppo privato</string> <string name="groups_invitation_sent">Invito a partecipare al gruppo spedito</string> - <string name="groups_compose_message">Scrivi un messaggio</string> <string name="groups_message_sent">Messaggio inviato</string> <string name="groups_member_list">Lista membri</string> <string name="groups_invite_members">Invita Membri</string> @@ -152,10 +151,6 @@ <item quantity="other">%d post</item> </plurals> <string name="forum_message_reply_hint">Nuova Risposta</string> - <plurals name="message_replies"> - <item quantity="one">risposta di %1$d</item> - <item quantity="other">risposte di %1$d</item> - </plurals> <string name="forum_leave">Lascia Forum</string> <string name="dialog_title_leave_forum">Conferma l\'abbandono del forum</string> <string name="dialog_button_leave">Lascia</string> @@ -261,4 +256,5 @@ <string name="send_report">Invia report</string> <string name="close">Chiudi</string> <!--Sign Out--> + <!--Screen Filters & Tapjacking--> </resources> diff --git a/briar-android/src/main/res/values-pt-rBR/strings.xml b/briar-android/src/main/res/values-pt-rBR/strings.xml index 51bda221940d3e33b842677fd1f8564bee3922ad..2160ce8736af898fd91d0383285dffdb0fb54b3a 100644 --- a/briar-android/src/main/res/values-pt-rBR/strings.xml +++ b/briar-android/src/main/res/values-pt-rBR/strings.xml @@ -151,7 +151,6 @@ <string name="groups_create_group_invitation_button">Enviar Convite</string> <string name="groups_create_group_hint">Adicionar um nome para seu grupo privado</string> <string name="groups_invitation_sent">Convite do Grupo enviado </string> - <string name="groups_compose_message">Escrever Mensagem</string> <string name="groups_message_sent">Mensagem enviada</string> <string name="groups_member_list">Lista de membros</string> <string name="groups_invite_members">Convidar membros</string> @@ -201,15 +200,10 @@ <item quantity="one">%d Post</item> <item quantity="other">%d Posts</item> </plurals> - <string name="forum_compose_post">Nova postagem em fórum</string> <string name="forum_new_entry_posted">postada com sucesso</string> <string name="forum_new_message_hint">Novo tópico</string> <string name="forum_message_reply_hint">Nova resposta</string> <string name="btn_reply">Responder</string> - <plurals name="message_replies"> - <item quantity="one">%1$d resposta</item> - <item quantity="other">%1$d respostas</item> - </plurals> <string name="forum_leave">Sair do fórum</string> <string name="dialog_title_leave_forum">Confirmar saÃda do fórum</string> <string name="dialog_message_leave_forum">Você tem certeza que deseja sair deste fórum? Seus contatos com quem você o compartilhou podem deixar de receber notificações dele.</string> @@ -349,4 +343,5 @@ <string name="dev_report_saved">Relatório salvo. Ele será enviado na próxima vez em que você entrar no Briar.</string> <!--Sign Out--> <string name="progress_title_logout">Saindo do Briar…</string> + <!--Screen Filters & Tapjacking--> </resources> diff --git a/briar-android/src/main/res/values-sq/strings.xml b/briar-android/src/main/res/values-sq/strings.xml index 72beba0aa91ecfe46cbac9fd484b827958c231d5..d4ce68a3ca2ed1f66ee5d7f0de34fcae4ca8aaaf 100644 --- a/briar-android/src/main/res/values-sq/strings.xml +++ b/briar-android/src/main/res/values-sq/strings.xml @@ -151,7 +151,6 @@ <string name="groups_create_group_invitation_button">Dërgoje Ftesën</string> <string name="groups_create_group_hint">Shtoni një emër për grupin tuaj privat</string> <string name="groups_invitation_sent">Ftesa e grupit u dërgua</string> - <string name="groups_compose_message">Hartoni Mesazh</string> <string name="groups_message_sent">Mesazhi u dërgua</string> <string name="groups_member_list">Listë Anëtarësh</string> <string name="groups_invite_members">Ftoni Anëtarë</string> @@ -182,6 +181,7 @@ <string name="groups_invitations_response_declined_sent">Hodhët poshtë ftesën e grupit nga %s.</string> <string name="groups_invitations_response_accepted_received">%s e pranoi ftesën e grupit.</string> <string name="groups_invitations_response_declined_received">%s e hodhi poshtë ftesën e grupit.</string> + <string name="sharing_status_groups">Vetëm krijuesi mund të ftojë anëtarë të rinj në grup. Më poshtë gjenden tërë anëtarët e tanishëm të grupit.</string> <!--Private Groups Revealing Contacts--> <string name="groups_reveal_contacts">Shfaqua Kontaktet</string> <string name="groups_reveal_dialog_message">Mund të zgjidhni t’ua shfaqni ose jo kontaktet krejt anëtarëve të tanishëm dhe të ardhshëm të këtij grupi.\n\nShfaqja e kontakteve e bën lidhjen tuaj me grupin më të shpejtë dhe më të besueshme, ngaqë mund të komunikoni me kontaktet e shfaqura edhe kur krijuesi i grupit s’është në linjë.</string> @@ -201,15 +201,10 @@ <item quantity="one">%d postim</item> <item quantity="other">%d postime</item> </plurals> - <string name="forum_compose_post">Postim i Ri Forumi</string> <string name="forum_new_entry_posted">U postua zë forumi</string> <string name="forum_new_message_hint">Zë i Ri</string> <string name="forum_message_reply_hint">Përgjigje e Re</string> <string name="btn_reply">Përgjigju</string> - <plurals name="message_replies"> - <item quantity="one">%1$d përgjigje</item> - <item quantity="other">%1$d përgjigje</item> - </plurals> <string name="forum_leave">Braktiseni Forumin</string> <string name="dialog_title_leave_forum">Ripohoni Braktisjen e Forumit</string> <string name="dialog_message_leave_forum">Jeni i sigurt se doni ta braktisni këtë forum? Kontaktet me të cilët e keni ndarë këtë forum mundet të mbeten jashtë marrjes së përditësimeve nga ky forum.</string> @@ -236,6 +231,7 @@ <string name="forum_invitation_response_accepted_received">%s pranoi ftesën e forumit.</string> <string name="forum_invitation_response_declined_received">%s e hodhi poshtë ftesën e forumit.</string> <string name="sharing_status">Gjendje Ndarjeje Me të Tjerë</string> + <string name="sharing_status_forum">Cilido anëtar i grupit mund ta ndajë me të tjerët. Këtë forum po e ndani me kontaktet vijuese. Mund të ketë edhe anëtarë të tjerët, të cilët s’mund t’i shihni.</string> <string name="shared_with">E ndarë me %1$d (%2$d në linjë)</string> <plurals name="forums_shared"> <item quantity="one">%d forum ndarë nga kontakte</item> @@ -273,6 +269,7 @@ <string name="blogs_sharing_invitations_title">Ftesa Blogu</string> <string name="blogs_sharing_joined_toast">U pajtuat te Blogu</string> <string name="blogs_sharing_declined_toast">Ftesa e Blogut u Hodh Poshtë</string> + <string name="sharing_status_blog">Cilido që pajtohet te një blog mund ta ndajë atë me kontaktet e veta. Këtë blog po e ndani me kontaktet vijuese. Mund të ketë edhe pajtimtarë të tjerë, të cilët s’mund t’i shihni.</string> <!--RSS Feeds--> <string name="blogs_rss_feeds_import">Importoni Prurje RSS</string> <string name="blogs_rss_feeds_import_button">Importo</string> @@ -282,6 +279,9 @@ <string name="blogs_rss_feeds_manage_imported">Të importuara:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_updated">Përditësuar Së Fundi:</string> + <string name="blogs_rss_remove_feed">Hiqe Prurjen</string> + <string name="blogs_rss_remove_feed_dialog_message">Jeni i sigurt se doni të hiqet kjo prurje dhe krejt postimet e saj?\nÇfarëdo postimi që keni ndarë me të tjerët, nuk do të hiqet nga pajisjet e personave të tjerë.</string> + <string name="blogs_rss_remove_feed_ok">Hiqe Prurjen</string> <string name="blogs_rss_feeds_manage_delete_error">S’u fshi dot prurja!</string> <string name="blogs_rss_feeds_manage_empty_state">S’keni importuar ende ndonjë prurje RSS.\n\nPse nuk klikoni mbi shenjën plus në cepin e sipërm djathtas që të shtoni të parën tuaj?</string> <string name="blogs_rss_feeds_manage_error">Pati një problem me ngarkimin e prurjeve tuaja. Ju lutemi, riprovoni më vonë.</string> @@ -353,4 +353,9 @@ <string name="dev_report_saved">Njoftimi u ruajt. Do të dërgohet herën tjetër që do të hyni në Briar.</string> <!--Sign Out--> <string name="progress_title_logout">Po dilet nga Briar-i…</string> + <!--Screen Filters & Tapjacking--> + <string name="screen_filter_title">U pikas filtër ekrani</string> + <string name="screen_filter_body">Aplikacionet vijuese kanë leje të vizatojnë përmbi aplikacione të tjera:\n\n%1$s \n\nBriar-i nuk do të reagojë ndaj prekjesh, kur mbi të po vizaton një tjetër aplikacion. +Nëse hasni probleme, provoni t’i mbyllni këto aplikacione, kur përdorni Briar-in.\n</string> + <string name="checkbox_dont_show_again">Mos më sinjalizo më për këto aplikacione</string> </resources> diff --git a/briar-android/src/main/res/values/color.xml b/briar-android/src/main/res/values/color.xml index daf3f8b3b2b07393fc0fb0993dd6931ac21b25ee..b9c28ffd2c0a8394a17d6487650889e3c80a55d2 100644 --- a/briar-android/src/main/res/values/color.xml +++ b/briar-android/src/main/res/values/color.xml @@ -33,11 +33,11 @@ <!-- this is needed as preference_category_material layout uses this color as the text color --> <color name="preference_fallback_accent_color">@color/briar_accent</color> + + <color name="thread_indicator">#9e9e9e</color> <color name="divider">#c1c1c1</color> - <color name="default_separator_inverted">#ffffff</color> <color name="menu_background">#FFFFFF</color> <color name="spinner_border">#61000000</color> <!-- 38% Black --> - <color name="forum_discussion_nested_line">#cfd2d4</color> <color name="forum_cell_highlight">#ffffff</color> </resources> \ No newline at end of file diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 3c8a44883027d77467b7189afeea387410c2bb32..42d6ba9f20868c07d5dd911c2aa25da3d6514d4e 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -162,7 +162,6 @@ <string name="groups_create_group_invitation_button">Send Invitation</string> <string name="groups_create_group_hint">Add a name for your private group</string> <string name="groups_invitation_sent">Group invitation has been sent</string> - <string name="groups_compose_message">Compose Message</string> <string name="groups_message_sent">Message sent</string> <string name="groups_member_list">Member List</string> <string name="groups_invite_members">Invite Members</string> @@ -216,15 +215,10 @@ <item quantity="one">%d post</item> <item quantity="other">%d posts</item> </plurals> - <string name="forum_compose_post">New Forum Post</string> <string name="forum_new_entry_posted">Forum entry posted</string> <string name="forum_new_message_hint">New Entry</string> <string name="forum_message_reply_hint">New Reply</string> <string name="btn_reply">Reply</string> - <plurals name="message_replies"> - <item quantity="one">%1$d reply</item> - <item quantity="other">%1$d replies</item> - </plurals> <string name="forum_leave">Leave Forum</string> <string name="dialog_title_leave_forum">Confirm Leaving Forum</string> <string name="dialog_message_leave_forum">Are you sure that you want to leave this forum? Contacts you have shared this forum with might get cut off from receiving updates for this forum.</string> diff --git a/briar-android/src/main/res/values/styles.xml b/briar-android/src/main/res/values/styles.xml index f599ac1899d3fcbb2954a3718909de8888bf2927..c967fdb0719cc839f1a06fe4c16e4c5c7f4b0e7a 100644 --- a/briar-android/src/main/res/values/styles.xml +++ b/briar-android/src/main/res/values/styles.xml @@ -102,7 +102,7 @@ <style name="DiscussionLevelIndicator"> <item name="android:layout_marginLeft">4dp</item> - <item name="android:background">@color/divider</item> + <item name="android:background">@color/thread_indicator</item> </style> <style name="BriarTabLayout" parent="Widget.Design.TabLayout"> diff --git a/briar-android/src/main/res/values/themes.xml b/briar-android/src/main/res/values/themes.xml index db57d78d40b380d4177193210e72b52abfb71f3c..f87a92356e8960835f47e34e1c0b682826753218 100644 --- a/briar-android/src/main/res/values/themes.xml +++ b/briar-android/src/main/res/values/themes.xml @@ -5,14 +5,8 @@ <item name="colorPrimary">@color/briar_primary</item> <item name="colorPrimaryDark">@color/briar_primary_dark</item> <item name="colorAccent">@color/briar_accent</item> - <item name="android:windowBackground">@color/window_background</item> - <item name="android:textColorPrimary">@color/briar_text_primary</item> - <item name="android:textColorPrimaryInverse">@color/briar_text_primary_inverse</item> - <item name="android:textColorSecondary">@color/briar_text_secondary</item> - <item name="android:textColorSecondaryInverse">@color/briar_text_secondary_inverse</item> - <item name="android:textColorTertiary">@color/briar_text_tertiary</item> - <item name="android:textColorTertiaryInverse">@color/briar_text_tertiary_inverse</item> <item name="android:textColorLink">@color/briar_text_link</item> + <item name="android:windowBackground">@color/window_background</item> <item name="android:windowAnimationStyle">@style/ActivityAnimation</item> <item name="android:filterTouchesWhenObscured">true</item> @@ -40,12 +34,6 @@ <item name="colorAccent">@color/briar_accent</item> <item name="buttonBarPositiveButtonStyle">@style/BriarButtonFlat.Positive</item> <item name="buttonBarNegativeButtonStyle">@style/BriarButtonFlat.Negative</item> - <item name="android:textColorPrimary">@color/briar_text_primary</item> - <item name="android:textColorPrimaryInverse">@color/briar_text_primary_inverse</item> - <item name="android:textColorSecondary">@color/briar_text_secondary</item> - <item name="android:textColorSecondaryInverse">@color/briar_text_secondary_inverse</item> - <item name="android:textColorTertiary">@color/briar_text_tertiary</item> - <item name="android:textColorTertiaryInverse">@color/briar_text_tertiary_inverse</item> <item name="android:textColorLink">@color/briar_text_link</item> <item name="android:windowAnimationStyle">@style/DialogAnimation</item> <item name="android:filterTouchesWhenObscured">true</item> diff --git a/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java b/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java index 8a3461c2eb1c4472cbf86a1d20db8ce08f06e8ff..96ffc88eb15de617846e5c5aba9d4c6242651f8d 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java @@ -13,6 +13,8 @@ import org.briarproject.briar.BuildConfig; import org.briarproject.briar.android.TestBriarApplication; import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler; import org.briarproject.briar.android.threaded.ThreadItemAdapter; +import org.briarproject.briar.android.threaded.ThreadItemList; +import org.briarproject.briar.android.threaded.ThreadItemListImpl; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -23,10 +25,7 @@ import org.robolectric.Robolectric; import org.robolectric.RobolectricGradleTestRunner; import org.robolectric.annotation.Config; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.List; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; @@ -81,7 +80,7 @@ public class ForumActivityTest { private TestForumActivity forumActivity; @Captor - private ArgumentCaptor<UiResultExceptionHandler<Collection<ForumItem>, DbException>> + private ArgumentCaptor<UiResultExceptionHandler<ThreadItemList<ForumItem>, DbException>> rc; @Before @@ -93,7 +92,7 @@ public class ForumActivityTest { .withIntent(intent).create().resume().get(); } - private List<ForumItem> getDummyData() { + private ThreadItemList<ForumItem> getDummyData() { ForumItem[] forumItems = new ForumItem[6]; for (int i = 0; i < forumItems.length; i++) { AuthorId authorId = new AuthorId(TestUtils.getRandomId()); @@ -103,13 +102,15 @@ public class ForumActivityTest { AUTHORS[i], System.currentTimeMillis(), author, UNKNOWN); forumItems[i].setLevel(LEVELS[i]); } - return new ArrayList<>(Arrays.asList(forumItems)); + ThreadItemList<ForumItem> list = new ThreadItemListImpl<>(); + list.addAll(Arrays.asList(forumItems)); + return list; } @Test public void testNestedEntries() { ForumController mc = forumActivity.getController(); - List<ForumItem> dummyData = getDummyData(); + ThreadItemList<ForumItem> dummyData = getDummyData(); verify(mc, times(1)).loadItems(rc.capture()); rc.getValue().onResult(dummyData); ThreadItemAdapter<ForumItem> adapter = forumActivity.getAdapter(); diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java index cce628fcb4e6f0092c60937ac227e2377c35c764..bc56ac377b7139a14d31518c763a169769ac7a0c 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java @@ -34,7 +34,7 @@ public interface BlogManager { /** * Returns true if a blog can be removed. */ - boolean canBeRemoved(GroupId g) throws DbException; + boolean canBeRemoved(Blog b) throws DbException; /** * Removes and deletes a blog. diff --git a/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTracker.java b/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTracker.java index 44c26fef4d583fc947e5e59e35954513c5ec3d98..5d6418f0aceaf17b46714509ec96c881187a31f1 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTracker.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/client/MessageTracker.java @@ -7,6 +7,8 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; +import javax.annotation.Nullable; + @NotNullByDefault public interface MessageTracker { @@ -38,6 +40,19 @@ public interface MessageTracker { void trackMessage(Transaction txn, GroupId g, long timestamp, boolean read) throws DbException; + /** + * Loads the stored message id for the respective group id or returns null + * if none is available. + */ + @Nullable + MessageId loadStoredMessageId(GroupId g) throws DbException; + + /** + * Stores the message id for the respective group id. Exactly one message id + * can be stored for any group id at any time, older values are overwritten. + */ + void storeMessageId(GroupId g, MessageId m) throws DbException; + /** * Marks a message as read or unread and updates the group count. */ diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java index 84f3724dafc341eec8391d56fa4535b47502c44f..cad04aa7ea64eb23156db131649029475e9e12a5 100644 --- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java @@ -3,7 +3,6 @@ package org.briarproject.briar.blog; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.contact.Contact; -import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfList; @@ -76,7 +75,6 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, AddContactHook, RemoveContactHook, Client { private final IdentityManager identityManager; - private final ContactManager contactManager; private final BlogFactory blogFactory; private final BlogPostFactory blogPostFactory; private final List<RemoveBlogHook> removeHooks; @@ -84,12 +82,10 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, @Inject BlogManagerImpl(DatabaseComponent db, IdentityManager identityManager, ClientHelper clientHelper, MetadataParser metadataParser, - ContactManager contactManager, BlogFactory blogFactory, - BlogPostFactory blogPostFactory) { + BlogFactory blogFactory, BlogPostFactory blogPostFactory) { super(db, clientHelper, metadataParser); this.identityManager = identityManager; - this.contactManager = contactManager; this.blogFactory = blogFactory; this.blogPostFactory = blogPostFactory; removeHooks = new CopyOnWriteArrayList<RemoveBlogHook>(); @@ -120,7 +116,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, @Override public void removingContact(Transaction txn, Contact c) throws DbException { Blog b = blogFactory.createBlog(c.getAuthor()); - removeBlog(txn, b, true); + removeBlog(txn, b); } @Override @@ -191,10 +187,10 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, } @Override - public boolean canBeRemoved(GroupId g) throws DbException { + public boolean canBeRemoved(Blog b) throws DbException { Transaction txn = db.startTransaction(true); try { - boolean canBeRemoved = canBeRemoved(txn, g); + boolean canBeRemoved = canBeRemoved(txn, b); db.commitTransaction(txn); return canBeRemoved; } finally { @@ -202,23 +198,18 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, } } - private boolean canBeRemoved(Transaction txn, GroupId g) + private boolean canBeRemoved(Transaction txn, Blog b) throws DbException { - boolean canBeRemoved; - Blog b = getBlog(txn, g); AuthorId authorId = b.getAuthor().getId(); LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); - if (localAuthor.getId().equals(authorId)) return false; - canBeRemoved = !contactManager - .contactExists(txn, authorId, localAuthor.getId()); - return canBeRemoved; + return !localAuthor.getId().equals(authorId); } @Override public void removeBlog(Blog b) throws DbException { Transaction txn = db.startTransaction(false); try { - removeBlog(txn, b, false); + removeBlog(txn, b); db.commitTransaction(txn); } finally { db.endTransaction(txn); @@ -227,12 +218,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, @Override public void removeBlog(Transaction txn, Blog b) throws DbException { - removeBlog(txn, b, false); - } - - private void removeBlog(Transaction txn, Blog b, boolean forced) - throws DbException { - if (!forced && !canBeRemoved(txn, b.getId())) + if (!canBeRemoved(txn, b)) throw new IllegalArgumentException(); for (RemoveBlogHook hook : removeHooks) hook.removingBlog(txn, b); diff --git a/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerConstants.java b/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerConstants.java index ca689fc1ca2543ecb6ae80e922831233a9daf319..81a1d603bfedd505c1b10f3ec4d321d862c27067 100644 --- a/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerConstants.java @@ -2,6 +2,7 @@ package org.briarproject.briar.client; public interface MessageTrackerConstants { + String GROUP_KEY_STORED_MESSAGE_ID = "storedMessageId"; String GROUP_KEY_MSG_COUNT = "messageCount"; String GROUP_KEY_UNREAD_COUNT = "unreadCount"; String GROUP_KEY_LATEST_MSG = "latestMessageTime"; diff --git a/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerImpl.java b/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerImpl.java index bd230dca8ea0ab8efda10cc9f1c6744a0186bbda..18e034027c906507119141a3b5e99993f9f7429d 100644 --- a/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/client/MessageTrackerImpl.java @@ -13,11 +13,13 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.client.MessageTracker; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_LATEST_MSG; import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_MSG_COUNT; +import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_STORED_MESSAGE_ID; import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_UNREAD_COUNT; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; @@ -57,6 +59,30 @@ class MessageTrackerImpl implements MessageTracker { latestMsgTime)); } + @Nullable + @Override + public MessageId loadStoredMessageId(GroupId g) throws DbException { + try { + BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(g); + byte[] msgBytes = d.getOptionalRaw(GROUP_KEY_STORED_MESSAGE_ID); + return msgBytes != null ? new MessageId(msgBytes) : null; + } catch (FormatException e) { + throw new DbException(e); + } + } + + @Override + public void storeMessageId(GroupId g, MessageId m) throws DbException { + BdfDictionary d = BdfDictionary.of( + new BdfEntry(GROUP_KEY_STORED_MESSAGE_ID, m) + ); + try { + clientHelper.mergeGroupMetadata(g, d); + } catch (FormatException e) { + throw new DbException(e); + } + } + @Override public GroupCount getGroupCount(GroupId g) throws DbException { GroupCount count; diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java index bb97bb0d48cf41956e00a4d89a84267e6792e7de..609166ad5673abc6540013d79b48b4bc0e031695 100644 --- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java @@ -467,7 +467,11 @@ class FeedManagerImpl implements FeedManager, Client, EventListener, // get other information for post GroupId groupId = feed.getBlogId(); - long time = clock.currentTimeMillis(); + long time, now = clock.currentTimeMillis(); + Date date = entry.getUpdatedDate(); + if (date == null) date = entry.getPublishedDate(); + if (date == null) time = now; + else time = Math.max(0, Math.min(date.getTime(), now)); String body = getPostBody(b.toString()); try { // create and store post diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java index 26da642ba270e9166e533637eef3feb15737707b..6664c67dcd64651494adace16accf196c5b62eb7 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java @@ -1,5 +1,6 @@ package org.briarproject.briar.sharing; +import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.client.ContactGroupFactory; import org.briarproject.bramble.api.contact.Contact; @@ -11,7 +12,6 @@ import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.ClientId; -import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogInvitationResponse; import org.briarproject.briar.api.blog.BlogManager; @@ -52,18 +52,17 @@ class BlogSharingManagerImpl extends SharingManagerImpl<Blog> } @Override - protected boolean canBeShared(Transaction txn, GroupId shareableId, - Contact c) throws DbException { - // check if shareableId belongs to our personal blog - LocalAuthor author = identityManager.getLocalAuthor(txn); - Blog b = blogManager.getPersonalBlog(author); - if (b.getId().equals(shareableId)) return false; - - // check if shareableId belongs to c's personal blog - b = blogManager.getPersonalBlog(c.getAuthor()); - if (b.getId().equals(shareableId)) return false; - - return super.canBeShared(txn, shareableId, c); + public void addingContact(Transaction txn, Contact c) throws DbException { + super.addingContact(txn, c); + LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); + Blog ourBlog = blogManager.getPersonalBlog(localAuthor); + Blog theirBlog = blogManager.getPersonalBlog(c.getAuthor()); + try { + initializeSharedSession(txn, c, ourBlog); + initializeSharedSession(txn, c, theirBlog); + } catch (FormatException e) { + throw new DbException(e); + } } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java index fc61bf49dfb266f986d1a88130409d2f136c5357..0b99d75bf61407d779f7f5026890c23a0f460bfb 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java @@ -48,6 +48,7 @@ import static org.briarproject.briar.sharing.MessageType.DECLINE; import static org.briarproject.briar.sharing.MessageType.INVITE; import static org.briarproject.briar.sharing.MessageType.LEAVE; import static org.briarproject.briar.sharing.SharingConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.briar.sharing.State.SHARING; @NotNullByDefault abstract class SharingManagerImpl<S extends Shareable> @@ -138,6 +139,16 @@ abstract class SharingManagerImpl<S extends Shareable> return false; } + protected void initializeSharedSession(Transaction txn, Contact c, + S shareable) throws DbException, FormatException { + GroupId contactGroupId = getContactGroup(c).getId(); + Session session = + new Session(SHARING, contactGroupId, shareable.getId(), null, + null, 0, 0); + MessageId storageId = createStorageId(txn, contactGroupId); + storeSession(txn, storageId, session); + } + private SessionId getSessionId(GroupId shareableId) { return new SessionId(shareableId.getBytes()); } @@ -414,7 +425,7 @@ abstract class SharingManagerImpl<S extends Shareable> } } - protected boolean canBeShared(Transaction txn, GroupId g, Contact c) + private boolean canBeShared(Transaction txn, GroupId g, Contact c) throws DbException { GroupId contactGroupId = getContactGroup(c).getId(); SessionId sessionId = getSessionId(g); diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java index ff5846c31c167a1f6447c4e3ff6fb23691a331e4..3678f1aba2bfa5e2a794935ceee7843f6a19a0da 100644 --- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java @@ -4,7 +4,6 @@ import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfList; @@ -77,8 +76,6 @@ public class BlogManagerImplTest extends BriarTestCase { private final IdentityManager identityManager = context.mock(IdentityManager.class); private final ClientHelper clientHelper = context.mock(ClientHelper.class); - private final ContactManager contactManager = - context.mock(ContactManager.class); private final BlogFactory blogFactory = context.mock(BlogFactory.class); private final BlogPostFactory blogPostFactory = context.mock(BlogPostFactory.class); @@ -94,7 +91,7 @@ public class BlogManagerImplTest extends BriarTestCase { public BlogManagerImplTest() { MetadataParser metadataParser = context.mock(MetadataParser.class); blogManager = new BlogManagerImpl(db, identityManager, clientHelper, - metadataParser, contactManager, blogFactory, blogPostFactory); + metadataParser, blogFactory, blogPostFactory); localAuthor1 = createLocalAuthor(); localAuthor2 = createLocalAuthor(); @@ -160,6 +157,8 @@ public class BlogManagerImplTest extends BriarTestCase { context.checking(new Expectations() {{ oneOf(blogFactory).createBlog(blog2.getAuthor()); will(returnValue(blog2)); + oneOf(identityManager).getLocalAuthor(txn); + will(returnValue(blog1.getAuthor())); oneOf(db).removeGroup(txn, blog2.getGroup()); }}); @@ -244,13 +243,11 @@ public class BlogManagerImplTest extends BriarTestCase { public void testRemoveBlog() throws Exception { final Transaction txn = new Transaction(null, false); - checkGetBlogExpectations(txn, false, blog1); context.checking(new Expectations() {{ + oneOf(db).startTransaction(false); + will(returnValue(txn)); oneOf(identityManager).getLocalAuthor(txn); will(returnValue(blog2.getAuthor())); - oneOf(contactManager).contactExists(txn, localAuthor1.getId(), - localAuthor2.getId()); - will(returnValue(false)); oneOf(db).removeGroup(txn, blog1.getGroup()); oneOf(db).commitTransaction(txn); oneOf(db).endTransaction(txn); @@ -800,57 +797,29 @@ public class BlogManagerImplTest extends BriarTestCase { public void testBlogCanBeRemoved() throws Exception { // check that own personal blogs can not be removed final Transaction txn = new Transaction(null, true); - checkGetBlogExpectations(txn, true, blog1); context.checking(new Expectations() {{ + oneOf(db).startTransaction(true); + will(returnValue(txn)); oneOf(identityManager).getLocalAuthor(txn); will(returnValue(blog1.getAuthor())); oneOf(db).commitTransaction(txn); oneOf(db).endTransaction(txn); }}); - assertFalse(blogManager.canBeRemoved(blog1.getId())); + assertFalse(blogManager.canBeRemoved(blog1)); context.assertIsSatisfied(); - // check that blogs of contacts can not be removed + // check that blogs of contacts can be removed final Transaction txn2 = new Transaction(null, true); - checkGetBlogExpectations(txn2, true, blog1); context.checking(new Expectations() {{ + oneOf(db).startTransaction(true); + will(returnValue(txn2)); oneOf(identityManager).getLocalAuthor(txn2); will(returnValue(blog2.getAuthor())); - oneOf(contactManager).contactExists(txn2, blog1.getAuthor().getId(), - blog2.getAuthor().getId()); - will(returnValue(true)); oneOf(db).commitTransaction(txn2); oneOf(db).endTransaction(txn2); }}); - assertFalse(blogManager.canBeRemoved(blog1.getId())); + assertTrue(blogManager.canBeRemoved(blog1)); context.assertIsSatisfied(); - - // check that blogs can be removed if they don't belong to a contact - final Transaction txn3 = new Transaction(null, true); - checkGetBlogExpectations(txn3, true, blog1); - context.checking(new Expectations() {{ - oneOf(identityManager).getLocalAuthor(txn3); - will(returnValue(blog2.getAuthor())); - oneOf(contactManager).contactExists(txn3, blog1.getAuthor().getId(), - blog2.getAuthor().getId()); - will(returnValue(false)); - oneOf(db).commitTransaction(txn3); - oneOf(db).endTransaction(txn3); - }}); - assertTrue(blogManager.canBeRemoved(blog1.getId())); - context.assertIsSatisfied(); - } - - private void checkGetBlogExpectations(final Transaction txn, - final boolean readOnly, final Blog blog) throws Exception { - context.checking(new Expectations() {{ - oneOf(db).startTransaction(readOnly); - will(returnValue(txn)); - oneOf(db).getGroup(txn, blog.getId()); - will(returnValue(blog.getGroup())); - oneOf(blogFactory).parseBlog(blog.getGroup()); - will(returnValue(blog)); - }}); } private LocalAuthor createLocalAuthor() { @@ -874,4 +843,4 @@ public class BlogManagerImplTest extends BriarTestCase { ); } -} +} \ No newline at end of file diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java index 289f3c09915e4259d4941d1d92280b312b0d203b..6c88846cf3c80b140b1bec6e1262d7ddf70443e7 100644 --- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java @@ -21,7 +21,6 @@ import org.junit.rules.ExpectedException; import java.util.Collection; import java.util.Iterator; -import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotNull; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; @@ -185,19 +184,19 @@ public class BlogManagerIntegrationTest } @Test - public void testCanNotRemoveContactsPersonalBlog() throws Exception { - assertFalse(blogManager0.canBeRemoved(blog1.getId())); - assertFalse(blogManager1.canBeRemoved(blog0.getId())); + public void testCanRemoveContactsPersonalBlog() throws Exception { + assertTrue(blogManager0.canBeRemoved(blog1)); + assertTrue(blogManager1.canBeRemoved(blog0)); - // the following two calls should throw a DbException now - thrown.expect(IllegalArgumentException.class); + assertEquals(4, blogManager0.getBlogs().size()); + assertEquals(2, blogManager1.getBlogs().size()); blogManager0.removeBlog(blog1); blogManager1.removeBlog(blog0); - // blogs have not been removed - assertEquals(2, blogManager0.getBlogs().size()); - assertEquals(2, blogManager1.getBlogs().size()); + // blogs have been removed + assertEquals(3, blogManager0.getBlogs().size()); + assertEquals(1, blogManager1.getBlogs().size()); } @Test diff --git a/briar-core/src/test/java/org/briarproject/briar/client/MessageTrackerTest.java b/briar-core/src/test/java/org/briarproject/briar/client/MessageTrackerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a7e8603202c358a92e625380282fbba3e35d619e --- /dev/null +++ b/briar-core/src/test/java/org/briarproject/briar/client/MessageTrackerTest.java @@ -0,0 +1,50 @@ +package org.briarproject.briar.client; + +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfEntry; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.test.BrambleMockTestCase; +import org.briarproject.bramble.test.TestUtils; +import org.briarproject.briar.api.client.MessageTracker; +import org.jmock.Expectations; +import org.junit.Assert; +import org.junit.Test; + +import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_STORED_MESSAGE_ID; + +public class MessageTrackerTest extends BrambleMockTestCase { + + protected final GroupId groupId = new GroupId(TestUtils.getRandomId()); + protected final ClientHelper clientHelper = + context.mock(ClientHelper.class); + private final DatabaseComponent db = context.mock(DatabaseComponent.class); + private final MessageId messageId = new MessageId(TestUtils.getRandomId()); + private final MessageTracker messageTracker = + new MessageTrackerImpl(db, clientHelper); + private final BdfDictionary dictionary = BdfDictionary.of( + new BdfEntry(GROUP_KEY_STORED_MESSAGE_ID, messageId) + ); + + @Test + public void testMessageStore() throws Exception { + context.checking(new Expectations() {{ + oneOf(clientHelper).mergeGroupMetadata(groupId, dictionary); + }}); + messageTracker.storeMessageId(groupId, messageId); + } + + @Test + public void testMessageLoad() throws Exception { + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(groupId); + will(returnValue(dictionary)); + }}); + MessageId loadedId = messageTracker.loadStoredMessageId(groupId); + Assert.assertNotNull(loadedId); + Assert.assertTrue(messageId.equals(loadedId)); + } + +} diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java index 31608a026130ef9d8514cf02b2b6c7fa42bed14e..e13718352e8a950e51058205bfdf238ad8ee5835 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java @@ -41,7 +41,7 @@ import static org.junit.Assert.fail; public class BlogSharingIntegrationTest extends BriarIntegrationTest<BriarIntegrationTestComponent> { - private BlogManager blogManager1; + private BlogManager blogManager0, blogManager1; private Blog blog0, blog1, blog2; private SharerListener listener0; private InviteeListener listener1; @@ -60,7 +60,7 @@ public class BlogSharingIntegrationTest public void setUp() throws Exception { super.setUp(); - BlogManager blogManager0 = c0.getBlogManager(); + blogManager0 = c0.getBlogManager(); blogManager1 = c1.getBlogManager(); blogSharingManager0 = c0.getBlogSharingManager(); blogSharingManager1 = c1.getBlogSharingManager(); @@ -370,7 +370,7 @@ public class BlogSharingIntegrationTest assertEquals(contact0From1, sharedBy.iterator().next()); // shared blog can be removed - assertTrue(blogManager1.canBeRemoved(blog2.getId())); + assertTrue(blogManager1.canBeRemoved(blog2)); // invitee removes blog again blogManager1.removeBlog(blog2); @@ -386,44 +386,33 @@ public class BlogSharingIntegrationTest } @Test - public void testSharedBlogBecomesPermanent() throws Exception { + public void testRemovePreSharedBlog() throws Exception { // let invitee accept all requests listenToEvents(true); - // invitee only sees two blogs - assertEquals(2, blogManager1.getBlogs().size()); + // 0 and 1 are sharing blog 1 with each other + assertTrue(blogSharingManager0.getSharedWith(blog1.getId()) + .contains(contact1From0)); + assertTrue(blogSharingManager1.getSharedWith(blog1.getId()) + .contains(contact0From1)); - // sharer sends invitation for 2's blog to 1 - blogSharingManager0 - .sendInvitation(blog2.getId(), contactId1From0, "Hi!", - clock.currentTimeMillis()); + // 0 removes blog 1 + assertTrue(blogManager0.getBlogs().contains(blog1)); + blogManager0.removeBlog(blog1); + assertFalse(blogManager0.getBlogs().contains(blog1)); - // sync first request message + // sync leave message to 0 sync0To1(1, true); - eventWaiter.await(TIMEOUT, 1); - assertTrue(listener1.requestReceived); - // make sure blog2 is shared by 0 - Collection<Contact> contacts = - blogSharingManager1.getSharedWith(blog2.getId()); - assertEquals(1, contacts.size()); - assertTrue(contacts.contains(contact0From1)); - - // sync response back - sync1To0(1, true); - eventWaiter.await(TIMEOUT, 1); - assertTrue(listener0.responseReceived); - - // blog was added and can be removed - assertEquals(3, blogManager1.getBlogs().size()); - assertTrue(blogManager1.canBeRemoved(blog2.getId())); - - // 1 and 2 are adding each other - addContacts1And2(); - assertEquals(3, blogManager1.getBlogs().size()); + // 0 and 1 are no longer sharing blog 1 with each other + assertFalse(blogSharingManager0.getSharedWith(blog1.getId()) + .contains(contact1From0)); + assertFalse(blogSharingManager1.getSharedWith(blog1.getId()) + .contains(contact0From1)); - // now blog can not be removed anymore - assertFalse(blogManager1.canBeRemoved(blog2.getId())); + // 1 can again share blog 1 with 0 + assertTrue( + blogSharingManager1.canBeShared(blog1.getId(), contact0From1)); } @Test