diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..950882915 --- /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 5ab9594f8..639155ac4 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 50c4e792a..9156b9caa 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 1fe9f31c6..be342f011 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 9494e6297..7f5cb0090 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 adc5265fb..fb0b1cd91 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 992304364..9394f9d02 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 c45608094..003c77ee7 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 e273d393d..9c12a7ace 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 cb195108a..6acf75255 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 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 apps = new HashSet<>(); private final Set 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 getShownScreenFilterApps() { - // res must not be modified - Set s = - prefs.getStringSet(PREF_SCREEN_FILTER_APPS, null); + // Result must not be modified + Set s = prefs.getStringSet(PREF_SCREEN_FILTER_APPS, null); HashSet 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 s, boolean persistent) { - HashSet buf = new HashSet(s); + HashSet 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 getInstalledScreenFilterApps() { HashSet screenFilterApps = new HashSet<>(); List 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 817822449..e148db65b 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 bfb689ef7..5521b9bea 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 ae666f691..414420dbd 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 e5cd225bc..c9305411d 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 33cf42232..839c0563b 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 eaeb7a06e..6ae01b8a5 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 c41df9f23..5c83206e5 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 ee82e165b..2af57aa1a 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 4c52f6154..8d97e7810 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 e20e814d6..248d4c49a 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 7999679ae..8c014237a 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 feaddbec9..c19aa38a2 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 0c7530559..db6029e57 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 a64769fdf..408fd29ba 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 5e7a64f56..30e80f829 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 d0adfef24..afede5594 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 11235ddbe..e916080bf 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 db44f92be..af709e937 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 4fd258d45..b07895d93 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 21c2e0ede..0fbf26f80 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 72b03a03f..21d0ede14 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 protected final NestedTreeList items = new NestedTreeList<>(); private final ThreadItemListener listener; private final LinearLayoutManager layoutManager; + private final Handler handler = new Handler(); private volatile int revision = 0; @@ -64,6 +67,17 @@ public class ThreadItemAdapter 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 items) { this.items.clear(); this.items.addAll(items); @@ -144,7 +158,7 @@ public class ThreadItemAdapter /** * 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 /** * 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 000000000..f517e8e9c --- /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 extends List { + + @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 000000000..2886607ed --- /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 extends ArrayList + implements ThreadItemList { + + 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 77ef46971..891615e02 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, I extends ThreadItem, H extends PostHeader> extends BriarActivity implements ThreadListListener, TextInputListener, SharingListener, - ThreadItemListener { + ThreadItemListener, 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 getController(); + @Inject protected SharingController sharingController; @@ -89,7 +88,6 @@ public abstract class ThreadListActivity, DbException>(this) { + new UiResultExceptionHandler, DbException>( + this) { @Override - public void onResultUi(Collection items) { + public void onResultUi(ThreadItemList 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 items) { + adapter.setItems(items); + MessageId messageId = items.getFirstVisibleItemId(); + if (messageId != null) + adapter.setItemWithIdVisible(messageId); + updateUnreadCount(); + list.showData(); + } + protected void loadSharingContacts() { getController().loadSharingContacts( new UiResultExceptionHandler, DbException>( @@ -231,18 +250,9 @@ public abstract class ThreadListActivity handler); - void loadItems(ResultExceptionHandler, DbException> handler); + void loadItems(ResultExceptionHandler, DbException> handler); void markItemRead(I item); @@ -41,7 +42,7 @@ public interface ThreadListController handler); - interface ThreadListListener extends DestroyableContext { + interface ThreadListListener extends ThreadListDataSource { @UiThread void onHeaderReceived(H header); @@ -52,4 +53,10 @@ public interface ThreadListController, DbException> handler) { + final ResultExceptionHandler, DbException> handler) { checkGroupId(); runOnDbThread(new Runnable() { @Override @@ -293,11 +308,16 @@ public abstract class ThreadListControllerImpl buildItems(Collection headers) { - List items = new ArrayList<>(); + private ThreadItemList buildItems(Collection headers) + throws DbException { + ThreadItemList 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 703747495..6dc2920ed 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 e7f4fa92f..0270cfea3 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 6f1f305df..000000000 --- a/briar-android/src/main/res/drawable/chevron48dp_down.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - 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 50894206e..000000000 --- a/briar-android/src/main/res/drawable/chevron48dp_up.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - 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 6d441fa06..167b7d7b9 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 @@ + android:pathData="M0,0 L30,0 L30,30 L0,30 L0,0 Z"/> + android:color="@color/thread_indicator"/> \ 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 f3a72a87d..000000000 --- a/briar-android/src/main/res/drawable/selector_chevron.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ 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 25b898dee..a8c8a1c36 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"/> - - - - Einladung schicken Gebe Deiner privaten Gruppe einen Namen Gruppeneinladung versendet - Nachricht erstellen Nachricht gesendet Mitglieder Mitglieder einladen @@ -174,14 +173,22 @@ %1$s hat dich eingeladen der Gruppe \"%2$s\" beizutreten. Gruppe beigetreten Gruppeneinladung abgelehnt + + %d offene Gruppeneinladung + %d offene Gruppeneinladungen + Gruppeneinladung von %s angenommen. Gruppeneinladung von %s abgelehnt. %s hat die Einladung zur Gruppe angenommen. %s hat die Einladung zur Gruppe abgelehnt. + Nur der Ersteller kann neue Mitglieder zu einer Gruppe einladen. HIer alle aktuellen Mitglieder dieser Gruppe. Kontakte teilen 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. Verbindung zum Kontakt ist für die Gruppe sichtbar + Beziehung zum Kontakt ist für diese Gruppe sichtbar (selbst offengelegt) + Beziehung zum Kontakt ist für diese Gruppe sichtbar (offengelegt durch %s) + Beziehung zum Kontakt ist für diese Gruppe nicht sichtbar 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. Neues Forum @@ -194,15 +201,10 @@ %d Beitrag %d Beiträge - Neuer Forenbeitrag Forenbeitrag wurde veröffentlicht. Neuer Eintrag Neue Antwort Antworten - - %1$d Antwort - %1$d Antworten - Forum verlassen Verlassen des Forums bestätigen 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. @@ -229,6 +231,8 @@ %s hat die Forumeinladung akzeptiert. %s hat die Forumseinladung abgelehnt. Sharing Status + 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. + Geteilt mit %1$d (%2$d online) %d Forum von Kontaken geteilt %d Foren von Kontakten geteilt @@ -265,6 +269,7 @@ Blogeinladungen Blog abonniert Blogeinladung abgelehnt + 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. RSS-Feed importieren Importieren @@ -274,6 +279,9 @@ Importiert: Autor: Letzte Aktualisierung: + Feed entfernen + Soll der Feed mit allen Posts wirklich gelöscht werden?\nGeteilte Posts werden dabei nicht von anderen Geräten gelöscht. + Feed entfernen Der Feed konnte nicht gelöscht werden! Du hast bisher noch keine RSS Feeds importiert. Tippe auf das \"+\"-Icon am oberen Bildschirmrand um einen neuen Feed hinzuzufügen. Es gab ein Problem beim Laden deiner Feeds. Bitte versuche es später erneut. @@ -282,6 +290,10 @@ Über Bluetooth verbinden Sobald Kontakte in der Nähe sind Nur beim Hinzufügen von Kontakten + Über Tor verbinden + Nie + Nur WLAN + WLAN oder mobile Datenverbindung Sicherheit Passwort ändern @@ -341,4 +353,9 @@ Der Bericht wurde gespeichert. Er wird verschickt, wenn Du Dich das nächste Mal bei Briar anmeldest. Von Briar abmelden ... + + Bildschirmfilter erkannt + 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 + Nicht noch einmal für diese Apps warnen diff --git a/briar-android/src/main/res/values-es/strings.xml b/briar-android/src/main/res/values-es/strings.xml index f4b7c982d..bd49a3f6e 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 @@ Enviar invitación Dar nombre al grupo privado Se ha mandado la invitación de grupo - Escribir mensaje Mensaje enviado Integrantes Invitar miembros @@ -182,6 +181,7 @@ Declinaste la invitación de grupo de %s. %s ha aceptado la invitación al grupo. %s ha declinado la invitación al grupo. + Solo el creador puede invitar nuevos miembros al grupo. Abajo se listan todos los participantes actuales. Revelar contactos 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. @@ -201,15 +201,10 @@ %d publicación %d publicaciones - Nueva publicación en el foro Entrada en el foro publicada Nueva entrada Nueva respuesta Responder - - %1$d respuesta - %1$d respuestas - Abandonar foro Confirmación abandono del foro ¿Seguro que quieres abandonar el foro? Puede que los contactos que invitaste al foro dejen de recibir actualizaciones del mismo. @@ -236,6 +231,7 @@ %s aceptó la invitación al foro. %s rechazó la invitación al foro. Estado de la compartición + 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. Compartido con %1$d (%2$d en línea) %d foro compartido por contactos @@ -273,6 +269,7 @@ Invitaciones a blogs Suscrito al blog Rechazada invitación al 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. Importar canal RSS Importar @@ -282,6 +279,9 @@ Importado: Autor: Última actualización: + Eliminar canal RSS + ¿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. + Eliminar canal RSS ¡El canal no pudo ser eliminado! 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? Hubo un problema cargando tus canales RSS. Por favor, prueba más tarde. @@ -290,6 +290,10 @@ Connectar mediante Bluetooth Cuando haya contactos cerca Solo al añadir contactos + Conectar a través de Tor + Nunca + Solo con wifi + Con wifi o datos móviles Seguridad Cambiar contraseña @@ -349,4 +353,9 @@ Informe guardado. Se enviará la próxima vez que inicies Briar. Saliendo de Briar… + + Filtro de pantalla detectado + 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 + No mostrar más para estas aplicaciones diff --git a/briar-android/src/main/res/values-fr/strings.xml b/briar-android/src/main/res/values-fr/strings.xml index 436149c56..4c91c4a6a 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 @@ 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. Briar n\'a pas pu démarrer Vous devrez peut-être réinstaller Briar. - Echec de démarrage de Briar. + Échec de démarrage de Briar 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. 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. Ce logiciel est arrivé à expiration.\nVeuillez installer une version plus récente. @@ -151,7 +151,6 @@ Envoyer invitation Ajouter un nom au groupe privé Invitation envoyée au groupe - Composer message Message envoyé Liste de participants Inviter des participants @@ -182,6 +181,7 @@ Vous avez refusé l\'invitation du groupe de %s. %s a accepté l\'invitation du groupe. %s a décliné l\'invitation du groupe. + Seul l\'initiateur du groupe peut inviter de nouveaux membres. Voici la liste des membres actuels. Dévoiler les contacts 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. @@ -201,15 +201,10 @@ %d message %d messages - Nouveau post de forum Entrée de forum postée Nouvelle entrée Nouvelle réponse Répondre - - %1$d réponse - %1$d réponses - Quitter le forum Confirmer la sortie du 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. @@ -236,6 +231,7 @@ %s a accepté l\'invitation au forum. %s a décliné l\'invitation au forum. Etat de partage + 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. Partagé avec %1$d (%2$d en ligne) %d forum partagé par des contacts @@ -273,6 +269,7 @@ Invitations au blog Abonné au Blog Invitation au blog refusée + 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. Import de flux RSS Importer @@ -282,6 +279,9 @@ Importé : Auteur : Dernière mise à jour : + Supprimer le flux + Ê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. + Supprimer le flux Le flux n\'a pas pu être supprimé ! Vous n\'avez importé aucun flux RSS.\n\nPourquoi ne pas cliquer le plus dans le coin en haut à droite pour ajouter votre premier ? Problème lors du chargement de vos flux. Réessayer ultérieurement. @@ -353,4 +353,9 @@ Rapport enregistré. Il sera envoyé lors de votre prochaine connexion à Briar. Déconnexion de Briar ... + + Filtre d\'écran détecté + 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 + Ne plus m\'avertir à propos de ces applications diff --git a/briar-android/src/main/res/values-it/strings.xml b/briar-android/src/main/res/values-it/strings.xml index 0c136181c..b905d0ec7 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 @@ Invia invito Inserisci un nome per il tuo gruppo privato Invito a partecipare al gruppo spedito - Scrivi un messaggio Messaggio inviato Lista membri Invita Membri @@ -152,10 +151,6 @@ %d post Nuova Risposta - - risposta di %1$d - risposte di %1$d - Lascia Forum Conferma l\'abbandono del forum Lascia @@ -261,4 +256,5 @@ Invia report Chiudi + 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 51bda2219..2160ce873 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 @@ Enviar Convite Adicionar um nome para seu grupo privado Convite do Grupo enviado - Escrever Mensagem Mensagem enviada Lista de membros Convidar membros @@ -201,15 +200,10 @@ %d Post %d Posts - Nova postagem em fórum postada com sucesso Novo tópico Nova resposta Responder - - %1$d resposta - %1$d respostas - Sair do fórum Confirmar saída do fórum Você tem certeza que deseja sair deste fórum? Seus contatos com quem você o compartilhou podem deixar de receber notificações dele. @@ -349,4 +343,5 @@ Relatório salvo. Ele será enviado na próxima vez em que você entrar no Briar. Saindo do Briar… + diff --git a/briar-android/src/main/res/values-sq/strings.xml b/briar-android/src/main/res/values-sq/strings.xml index 72beba0aa..d4ce68a3c 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 @@ Dërgoje Ftesën Shtoni një emër për grupin tuaj privat Ftesa e grupit u dërgua - Hartoni Mesazh Mesazhi u dërgua Listë Anëtarësh Ftoni Anëtarë @@ -182,6 +181,7 @@ Hodhët poshtë ftesën e grupit nga %s. %s e pranoi ftesën e grupit. %s e hodhi poshtë ftesën e grupit. + 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. Shfaqua Kontaktet 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ë. @@ -201,15 +201,10 @@ %d postim %d postime - Postim i Ri Forumi U postua zë forumi Zë i Ri Përgjigje e Re Përgjigju - - %1$d përgjigje - %1$d përgjigje - Braktiseni Forumin Ripohoni Braktisjen e Forumit 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. @@ -236,6 +231,7 @@ %s pranoi ftesën e forumit. %s e hodhi poshtë ftesën e forumit. Gjendje Ndarjeje Me të Tjerë + 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. E ndarë me %1$d (%2$d në linjë) %d forum ndarë nga kontakte @@ -273,6 +269,7 @@ Ftesa Blogu U pajtuat te Blogu Ftesa e Blogut u Hodh Poshtë + 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. Importoni Prurje RSS Importo @@ -282,6 +279,9 @@ Të importuara: Autor: Përditësuar Së Fundi: + Hiqe Prurjen + 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ë. + Hiqe Prurjen S’u fshi dot prurja! 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? Pati një problem me ngarkimin e prurjeve tuaja. Ju lutemi, riprovoni më vonë. @@ -353,4 +353,9 @@ Njoftimi u ruajt. Do të dërgohet herën tjetër që do të hyni në Briar. Po dilet nga Briar-i… + + U pikas filtër ekrani + 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 + Mos më sinjalizo më për këto aplikacione diff --git a/briar-android/src/main/res/values/color.xml b/briar-android/src/main/res/values/color.xml index daf3f8b3b..b9c28ffd2 100644 --- a/briar-android/src/main/res/values/color.xml +++ b/briar-android/src/main/res/values/color.xml @@ -33,11 +33,11 @@ @color/briar_accent + + #9e9e9e #c1c1c1 - #ffffff #FFFFFF #61000000 - #cfd2d4 #ffffff \ 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 3c8a44883..42d6ba9f2 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -162,7 +162,6 @@ Send Invitation Add a name for your private group Group invitation has been sent - Compose Message Message sent Member List Invite Members @@ -216,15 +215,10 @@ %d post %d posts - New Forum Post Forum entry posted New Entry New Reply Reply - - %1$d reply - %1$d replies - Leave Forum Confirm Leaving 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. diff --git a/briar-android/src/main/res/values/styles.xml b/briar-android/src/main/res/values/styles.xml index f599ac189..c967fdb07 100644 --- a/briar-android/src/main/res/values/styles.xml +++ b/briar-android/src/main/res/values/styles.xml @@ -102,7 +102,7 @@