mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Compare commits
33 Commits
beta-1.5.4
...
client-ver
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72136cc627 | ||
|
|
411ace13aa | ||
|
|
952ee42ad1 | ||
|
|
f61b09d5a9 | ||
|
|
8f735d176e | ||
|
|
c47253fc5f | ||
|
|
7a0fb74c09 | ||
|
|
882f536b8d | ||
|
|
74f8e84a9b | ||
|
|
23df2a41c2 | ||
|
|
c77eaf16d9 | ||
|
|
9a6bb4b203 | ||
|
|
3d237a9104 | ||
|
|
fa216ffc6f | ||
|
|
a34631d36c | ||
|
|
45cda191e5 | ||
|
|
2495b6f5c0 | ||
|
|
03fc504f7d | ||
|
|
d19062e319 | ||
|
|
fdb429ab7a | ||
|
|
d0c59a6d75 | ||
|
|
3bb39c2aa3 | ||
|
|
917fc5e5b6 | ||
|
|
caa078585b | ||
|
|
e68c0c7f4b | ||
|
|
a6b3749fb6 | ||
|
|
a8f6e8e4bd | ||
|
|
4d884601f0 | ||
|
|
b71198d9b1 | ||
|
|
079c6e0475 | ||
|
|
3a0f8ed85c | ||
|
|
57f7501780 | ||
|
|
3cc5699fe0 |
@@ -12,7 +12,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 31
|
targetSdkVersion 33
|
||||||
versionCode 10504
|
versionCode 10504
|
||||||
versionName "1.5.4"
|
versionName "1.5.4"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.battery.BatteryManager;
|
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||||
import org.briarproject.bramble.api.battery.event.BatteryEvent;
|
import org.briarproject.bramble.api.battery.event.BatteryEvent;
|
||||||
@@ -16,10 +17,17 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
import static android.content.Intent.ACTION_BATTERY_CHANGED;
|
import static android.content.Intent.ACTION_BATTERY_CHANGED;
|
||||||
import static android.content.Intent.ACTION_POWER_CONNECTED;
|
import static android.content.Intent.ACTION_POWER_CONNECTED;
|
||||||
import static android.content.Intent.ACTION_POWER_DISCONNECTED;
|
import static android.content.Intent.ACTION_POWER_DISCONNECTED;
|
||||||
import static android.os.BatteryManager.EXTRA_PLUGGED;
|
import static android.os.BatteryManager.EXTRA_PLUGGED;
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
|
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
||||||
|
import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED;
|
||||||
|
import static android.os.PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED;
|
||||||
|
import static android.os.PowerManager.ACTION_POWER_SAVE_MODE_CHANGED;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
@@ -57,6 +65,12 @@ class AndroidBatteryManager implements BatteryManager, Service {
|
|||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(ACTION_POWER_CONNECTED);
|
filter.addAction(ACTION_POWER_CONNECTED);
|
||||||
filter.addAction(ACTION_POWER_DISCONNECTED);
|
filter.addAction(ACTION_POWER_DISCONNECTED);
|
||||||
|
filter.addAction(ACTION_POWER_SAVE_MODE_CHANGED);
|
||||||
|
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
|
||||||
|
if (SDK_INT >= 33) {
|
||||||
|
filter.addAction(ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
|
||||||
|
filter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED);
|
||||||
|
}
|
||||||
appContext.registerReceiver(batteryReceiver, filter);
|
appContext.registerReceiver(batteryReceiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +90,33 @@ class AndroidBatteryManager implements BatteryManager, Service {
|
|||||||
eventBus.broadcast(new BatteryEvent(true));
|
eventBus.broadcast(new BatteryEvent(true));
|
||||||
else if (ACTION_POWER_DISCONNECTED.equals(action))
|
else if (ACTION_POWER_DISCONNECTED.equals(action))
|
||||||
eventBus.broadcast(new BatteryEvent(false));
|
eventBus.broadcast(new BatteryEvent(false));
|
||||||
|
else if (SDK_INT >= 23 &&
|
||||||
|
ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action) &&
|
||||||
|
LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info("Device idle mode changed to: " +
|
||||||
|
getPowerManager(ctx).isDeviceIdleMode());
|
||||||
|
} else if (SDK_INT >= 23 &&
|
||||||
|
ACTION_POWER_SAVE_MODE_CHANGED.equals(action) &&
|
||||||
|
LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info("Power save mode changed to: " +
|
||||||
|
getPowerManager(ctx).isPowerSaveMode());
|
||||||
|
} else if (SDK_INT >= 33 && LOG.isLoggable(INFO) &&
|
||||||
|
ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED.equals(action)) {
|
||||||
|
PowerManager powerManager =
|
||||||
|
ctx.getSystemService(PowerManager.class);
|
||||||
|
LOG.info("Low power standby now is: " +
|
||||||
|
powerManager.isLowPowerStandbyEnabled());
|
||||||
|
} else if (SDK_INT >= 33 && LOG.isLoggable(INFO) &&
|
||||||
|
ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED.equals(action)) {
|
||||||
|
PowerManager powerManager = getPowerManager(ctx);
|
||||||
|
LOG.info("Light idle mode now is: " +
|
||||||
|
powerManager.isDeviceLightIdleMode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = 23)
|
||||||
|
private PowerManager getPowerManager(Context ctx) {
|
||||||
|
return ctx.getSystemService(PowerManager.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,10 +63,12 @@ public class AndroidUtils {
|
|||||||
return new Pair<>(address, "adapter");
|
return new Pair<>(address, "adapter");
|
||||||
}
|
}
|
||||||
// Return the address from settings if it's valid and not fake
|
// Return the address from settings if it's valid and not fake
|
||||||
address = Settings.Secure.getString(ctx.getContentResolver(),
|
if (SDK_INT < 33) {
|
||||||
"bluetooth_address");
|
address = Settings.Secure.getString(ctx.getContentResolver(),
|
||||||
if (isValidBluetoothAddress(address)) {
|
"bluetooth_address");
|
||||||
return new Pair<>(address, "settings");
|
if (isValidBluetoothAddress(address)) {
|
||||||
|
return new Pair<>(address, "settings");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Try to get the address via reflection
|
// Try to get the address via reflection
|
||||||
address = getBluetoothAddressByReflection(adapter);
|
address = getBluetoothAddressByReflection(adapter);
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ dependencyVerification {
|
|||||||
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
||||||
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
||||||
'org.briarproject:obfs4proxy-android:0.0.14-tor2:obfs4proxy-android-0.0.14-tor2.jar:a0a93770d6760ce57d9dbd31cc7177687374e00c3361dac22ab75e3b6e0f289e',
|
'org.briarproject:obfs4proxy-android:0.0.14-tor2:obfs4proxy-android-0.0.14-tor2.jar:a0a93770d6760ce57d9dbd31cc7177687374e00c3361dac22ab75e3b6e0f289e',
|
||||||
'org.briarproject:onionwrapper-android:0.0.2:onionwrapper-android-0.0.2.aar:d196f1fe5d8b750866ea09d80509716aae7645d39b2c85433994718dbebeb4d1',
|
'org.briarproject:onionwrapper-android:0.0.4:onionwrapper-android-0.0.4.aar:d761854dac454616b3e0ca099b2cd17060365ce4316afe495cc7ae86b6c81d15',
|
||||||
'org.briarproject:onionwrapper-core:0.0.2:onionwrapper-core-0.0.2.jar:7038e960c9e59803f0e2c19444dbb5214cd99e5a7463c0a01c45318e07a0eb80',
|
'org.briarproject:onionwrapper-core:0.0.4:onionwrapper-core-0.0.4.jar:28a01a62e96aa763989a8afc325abd3bee54f8021269f91aa48b247a6e717870',
|
||||||
'org.briarproject:snowflake-android:2.5.1:snowflake-android-2.5.1.jar:88ec81c17b1b6fa884d06839dec0330e328b45c89f88c970a213ce91ca8eac87',
|
'org.briarproject:snowflake-android:2.5.1:snowflake-android-2.5.1.jar:88ec81c17b1b6fa884d06839dec0330e328b45c89f88c970a213ce91ca8eac87',
|
||||||
'org.briarproject:tor-android:0.4.7.13-2:tor-android-0.4.7.13-2.jar:453fd463b234a2104edd7f0d02d0649cbb5c5efbe47a76df3828f55a3f90f8b5',
|
'org.briarproject:tor-android:0.4.7.13-2:tor-android-0.4.7.13-2.jar:453fd463b234a2104edd7f0d02d0649cbb5c5efbe47a76df3828f55a3f90f8b5',
|
||||||
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.api.network;
|
|||||||
|
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -27,4 +28,20 @@ public class NetworkStatus {
|
|||||||
public boolean isIpv6Only() {
|
public boolean isIpv6Only() {
|
||||||
return ipv6Only;
|
return ipv6Only;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (connected ? 1 : 0) | (wifi ? 2 : 0) | (ipv6Only ? 4 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object o) {
|
||||||
|
if (o instanceof NetworkStatus) {
|
||||||
|
NetworkStatus s = (NetworkStatus) o;
|
||||||
|
return connected == s.connected
|
||||||
|
&& wifi == s.wifi
|
||||||
|
&& ipv6Only == s.ipv6Only;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,6 +311,9 @@ class TorPlugin implements DuplexPlugin, EventListener {
|
|||||||
tor.stop();
|
tor.stop();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOG.warning("Interrupted while stopping Tor");
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,12 +628,23 @@ class TorPlugin implements DuplexPlugin, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized State getState(TorState torState) {
|
private synchronized State getState(TorState torState) {
|
||||||
if (torState == TorState.STARTING_STOPPING || !settingsChecked) {
|
// Treat TorState.STARTED as State.STARTING_STOPPING because it's
|
||||||
|
// only seen during startup, before TorWrapper#enableNetwork() is
|
||||||
|
// called for the first time. TorState.NOT_STARTED and
|
||||||
|
// TorState.STOPPED are mapped to State.STARTING_STOPPING because
|
||||||
|
// that's the State before we've started and after we've stopped.
|
||||||
|
if (torState == TorState.NOT_STARTED ||
|
||||||
|
torState == TorState.STARTING ||
|
||||||
|
torState == TorState.STARTED ||
|
||||||
|
torState == TorState.STOPPING ||
|
||||||
|
torState == TorState.STOPPED ||
|
||||||
|
!settingsChecked) {
|
||||||
return STARTING_STOPPING;
|
return STARTING_STOPPING;
|
||||||
}
|
}
|
||||||
if (reasonsDisabled != 0) return DISABLED;
|
if (reasonsDisabled != 0) return DISABLED;
|
||||||
if (torState == TorState.CONNECTING) return ENABLING;
|
if (torState == TorState.CONNECTING) return ENABLING;
|
||||||
if (torState == TorState.CONNECTED) return ACTIVE;
|
if (torState == TorState.CONNECTED) return ACTIVE;
|
||||||
|
// The plugin is enabled in settings but the device is offline
|
||||||
return INACTIVE;
|
return INACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.briarproject.bramble.api.sync.GroupId;
|
|||||||
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
|
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.versioning.ClientMajorVersion;
|
import org.briarproject.bramble.api.versioning.ClientMajorVersion;
|
||||||
@@ -36,17 +37,20 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
|
||||||
@@ -58,6 +62,9 @@ import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_
|
|||||||
class ClientVersioningManagerImpl implements ClientVersioningManager,
|
class ClientVersioningManagerImpl implements ClientVersioningManager,
|
||||||
Service, OpenDatabaseHook, ContactHook, IncomingMessageHook {
|
Service, OpenDatabaseHook, ContactHook, IncomingMessageHook {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
getLogger(ClientVersioningManagerImpl.class.getName());
|
||||||
|
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final ClientHelper clientHelper;
|
private final ClientHelper clientHelper;
|
||||||
private final ContactGroupFactory contactGroupFactory;
|
private final ContactGroupFactory contactGroupFactory;
|
||||||
@@ -128,12 +135,68 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDatabaseOpened(Transaction txn) throws DbException {
|
public void onDatabaseOpened(Transaction txn) throws DbException {
|
||||||
|
LOG.info("onDatabaseOpened " + localGroup.getId());
|
||||||
|
for (Contact c : db.getContacts(txn)) {
|
||||||
|
try {
|
||||||
|
// FIXME: DO NOT MERGE, this logs the contact name and alias
|
||||||
|
LOG.info(String.format(Locale.US,
|
||||||
|
"find latest updates for %d: %s (%s)",
|
||||||
|
c.getId().getInt(),
|
||||||
|
c.getAuthor().getName(),
|
||||||
|
c.getAlias()));
|
||||||
|
LatestUpdates latestUpdates = findLatestUpdates(txn, c.getId());
|
||||||
|
if (latestUpdates == null) {
|
||||||
|
LOG.info("none found");
|
||||||
|
} else {
|
||||||
|
if (latestUpdates.local != null) {
|
||||||
|
MessageStatus status = db.getMessageStatus(txn,
|
||||||
|
c.getId(), latestUpdates.local.messageId);
|
||||||
|
LOG.info(String.format(Locale.US,
|
||||||
|
"local: %s; sent: %b; seen: %b%n",
|
||||||
|
latestUpdates.local.messageId,
|
||||||
|
status.isSent(),
|
||||||
|
status.isSeen()));
|
||||||
|
Update update =
|
||||||
|
loadUpdate(txn, latestUpdates.local.messageId);
|
||||||
|
printUpdate(update);
|
||||||
|
}
|
||||||
|
if (latestUpdates.remote != null) {
|
||||||
|
MessageStatus status = db.getMessageStatus(txn,
|
||||||
|
c.getId(), latestUpdates.remote.messageId);
|
||||||
|
LOG.info(String.format(Locale.US,
|
||||||
|
"remote: %s; sent: %b; seen: %b%n",
|
||||||
|
latestUpdates.remote.messageId,
|
||||||
|
status.isSent(),
|
||||||
|
status.isSeen()));
|
||||||
|
Update update =
|
||||||
|
loadUpdate(txn, latestUpdates.remote.messageId);
|
||||||
|
printUpdate(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (db.containsGroup(txn, localGroup.getId())) return;
|
if (db.containsGroup(txn, localGroup.getId())) return;
|
||||||
db.addGroup(txn, localGroup);
|
db.addGroup(txn, localGroup);
|
||||||
// Set things up for any pre-existing contacts
|
// Set things up for any pre-existing contacts
|
||||||
for (Contact c : db.getContacts(txn)) addingContact(txn, c);
|
for (Contact c : db.getContacts(txn)) addingContact(txn, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void printUpdate(Update update) {
|
||||||
|
LOG.info(String.format(Locale.US, "update version: %d%n",
|
||||||
|
update.updateVersion));
|
||||||
|
for (ClientState state : update.states) {
|
||||||
|
LOG.info(String.format(Locale.US,
|
||||||
|
"id: %s, major: %d, minor: %d, active: %b, %n",
|
||||||
|
state.clientVersion.getClientId().getString(),
|
||||||
|
state.clientVersion.getClientMajorVersion()
|
||||||
|
.getMajorVersion(),
|
||||||
|
state.clientVersion.getMinorVersion(),
|
||||||
|
state.active));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startService() throws ServiceException {
|
public void startService() throws ServiceException {
|
||||||
List<ClientVersion> versions = new ArrayList<>(clients);
|
List<ClientVersion> versions = new ArrayList<>(clients);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ dependencyVerification {
|
|||||||
'org.bouncycastle:bcprov-jdk15to18:1.71:bcprov-jdk15to18-1.71.jar:143aaa4a40edd5fc2a18db7900059f6c16f4d931b94b94b20f7e2238e6662886',
|
'org.bouncycastle:bcprov-jdk15to18:1.71:bcprov-jdk15to18-1.71.jar:143aaa4a40edd5fc2a18db7900059f6c16f4d931b94b94b20f7e2238e6662886',
|
||||||
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
||||||
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
||||||
'org.briarproject:onionwrapper-core:0.0.2:onionwrapper-core-0.0.2.jar:7038e960c9e59803f0e2c19444dbb5214cd99e5a7463c0a01c45318e07a0eb80',
|
'org.briarproject:onionwrapper-core:0.0.4:onionwrapper-core-0.0.4.jar:28a01a62e96aa763989a8afc325abd3bee54f8021269f91aa48b247a6e717870',
|
||||||
'org.briarproject:socks-socket:0.1:socks-socket-0.1.jar:e5898822d10f5390363c5dddb945891648c92cf93ba50709e07f0d173ec0eb4b',
|
'org.briarproject:socks-socket:0.1:socks-socket-0.1.jar:e5898822d10f5390363c5dddb945891648c92cf93ba50709e07f0d173ec0eb4b',
|
||||||
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
||||||
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ dependencies {
|
|||||||
implementation project(':bramble-core')
|
implementation project(':bramble-core')
|
||||||
|
|
||||||
implementation fileTree(dir: 'libs', include: '*.jar')
|
implementation fileTree(dir: 'libs', include: '*.jar')
|
||||||
def jna_version = '4.5.2'
|
def jna_version = '5.13.0'
|
||||||
implementation "net.java.dev.jna:jna:$jna_version"
|
implementation "net.java.dev.jna:jna:$jna_version"
|
||||||
implementation "net.java.dev.jna:jna-platform:$jna_version"
|
implementation "net.java.dev.jna:jna-platform:$jna_version"
|
||||||
implementation "org.briarproject:onionwrapper-java:$onionwrapper_version"
|
implementation "org.briarproject:onionwrapper-java:$onionwrapper_version"
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.network.JavaNetworkModule;
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface BrambleJavaEagerSingletons {
|
||||||
|
|
||||||
|
void inject(JavaNetworkModule.EagerSingletons init);
|
||||||
|
|
||||||
|
class Helper {
|
||||||
|
|
||||||
|
public static void injectEagerSingletons(BrambleJavaEagerSingletons c) {
|
||||||
|
c.inject(new JavaNetworkModule.EagerSingletons());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +1,51 @@
|
|||||||
package org.briarproject.bramble.network;
|
package org.briarproject.bramble.network;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.Service;
|
||||||
import org.briarproject.bramble.api.network.NetworkManager;
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
import org.briarproject.bramble.api.network.NetworkStatus;
|
import org.briarproject.bramble.api.network.NetworkStatus;
|
||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
|
||||||
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.Collections.list;
|
import static java.util.Collections.list;
|
||||||
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.NetworkUtils.getNetworkInterfaces;
|
import static org.briarproject.bramble.util.NetworkUtils.getNetworkInterfaces;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@NotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
class JavaNetworkManager implements NetworkManager, Service {
|
||||||
class JavaNetworkManager implements NetworkManager {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(JavaNetworkManager.class.getName());
|
getLogger(JavaNetworkManager.class.getName());
|
||||||
|
|
||||||
|
private final TaskScheduler scheduler;
|
||||||
|
private final Executor ioExecutor;
|
||||||
|
private final EventBus eventBus;
|
||||||
|
private final AtomicReference<NetworkStatus> lastStatus =
|
||||||
|
new AtomicReference<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
JavaNetworkManager() {
|
JavaNetworkManager(TaskScheduler scheduler,
|
||||||
|
@IoExecutor Executor ioExecutor,
|
||||||
|
EventBus eventBus) {
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.eventBus = eventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -48,7 +66,29 @@ class JavaNetworkManager implements NetworkManager {
|
|||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info("Connected: " + connected
|
||||||
|
+ ", has IPv4 address: " + hasIpv4
|
||||||
|
+ ", has IPv6 unicast address: " + hasIpv6Unicast);
|
||||||
|
}
|
||||||
return new NetworkStatus(connected, false, !hasIpv4 && hasIpv6Unicast);
|
return new NetworkStatus(connected, false, !hasIpv4 && hasIpv6Unicast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void broadcastNetworkStatusIfChanged() {
|
||||||
|
NetworkStatus status = getNetworkStatus();
|
||||||
|
NetworkStatus old = lastStatus.getAndSet(status);
|
||||||
|
if (!status.equals(old)) {
|
||||||
|
eventBus.broadcast(new NetworkStatusEvent(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startService() {
|
||||||
|
scheduler.scheduleWithFixedDelay(this::broadcastNetworkStatusIfChanged,
|
||||||
|
ioExecutor, 0, 10, SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopService() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package org.briarproject.bramble.network;
|
package org.briarproject.bramble.network;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.network.NetworkManager;
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
@@ -10,9 +12,16 @@ import dagger.Provides;
|
|||||||
@Module
|
@Module
|
||||||
public class JavaNetworkModule {
|
public class JavaNetworkModule {
|
||||||
|
|
||||||
|
public static class EagerSingletons {
|
||||||
|
@Inject
|
||||||
|
NetworkManager networkManager;
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
NetworkManager provideNetworkManager(JavaNetworkManager networkManager) {
|
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,
|
||||||
|
JavaNetworkManager networkManager) {
|
||||||
|
lifecycleManager.registerService(networkManager);
|
||||||
return networkManager;
|
return networkManager;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package org.briarproject.bramble.plugin.tor;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.event.EventExecutor;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
|
import org.briarproject.bramble.api.plugin.PluginCallback;
|
||||||
|
import org.briarproject.bramble.api.plugin.TorControlPort;
|
||||||
|
import org.briarproject.bramble.api.plugin.TorDirectory;
|
||||||
|
import org.briarproject.bramble.api.plugin.TorSocksPort;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.bramble.api.system.WakefulIoExecutor;
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.onionwrapper.CircumventionProvider;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
|
import org.briarproject.onionwrapper.MacTorWrapper;
|
||||||
|
import org.briarproject.onionwrapper.TorWrapper;
|
||||||
|
import org.briarproject.onionwrapper.UnixTorWrapper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static org.briarproject.bramble.util.OsUtils.isMac;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class MacTorPluginFactory extends TorPluginFactory {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MacTorPluginFactory(@IoExecutor Executor ioExecutor,
|
||||||
|
@EventExecutor Executor eventExecutor,
|
||||||
|
@WakefulIoExecutor Executor wakefulIoExecutor,
|
||||||
|
NetworkManager networkManager,
|
||||||
|
LocationUtils locationUtils,
|
||||||
|
EventBus eventBus,
|
||||||
|
SocketFactory torSocketFactory,
|
||||||
|
BackoffFactory backoffFactory,
|
||||||
|
CircumventionProvider circumventionProvider,
|
||||||
|
BatteryManager batteryManager,
|
||||||
|
Clock clock,
|
||||||
|
CryptoComponent crypto,
|
||||||
|
@TorDirectory File torDirectory,
|
||||||
|
@TorSocksPort int torSocksPort,
|
||||||
|
@TorControlPort int torControlPort) {
|
||||||
|
super(ioExecutor, eventExecutor, wakefulIoExecutor, networkManager,
|
||||||
|
locationUtils, eventBus, torSocketFactory, backoffFactory,
|
||||||
|
circumventionProvider, batteryManager, clock, crypto,
|
||||||
|
torDirectory, torSocksPort, torControlPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
String getArchitectureForTorBinary() {
|
||||||
|
if (!isMac()) return null;
|
||||||
|
String arch = System.getProperty("os.arch");
|
||||||
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info("System's os.arch is " + arch);
|
||||||
|
}
|
||||||
|
if (arch.equals("x86_64")) return "x86_64";
|
||||||
|
else if (arch.equals("aarch64")) return "aarch64";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
TorPlugin createPluginInstance(Backoff backoff,
|
||||||
|
TorRendezvousCrypto torRendezvousCrypto, PluginCallback callback,
|
||||||
|
String architecture) {
|
||||||
|
TorWrapper tor = new MacTorWrapper(ioExecutor, eventExecutor,
|
||||||
|
architecture, torDirectory, torSocksPort, torControlPort);
|
||||||
|
return new TorPlugin(ioExecutor, wakefulIoExecutor, networkManager,
|
||||||
|
locationUtils, torSocketFactory, circumventionProvider,
|
||||||
|
batteryManager, backoff, torRendezvousCrypto, tor, callback,
|
||||||
|
MAX_LATENCY, MAX_IDLE_TIME, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,15 +20,15 @@ dependencyVerification {
|
|||||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
||||||
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
||||||
'net.java.dev.jna:jna-platform:4.5.2:jna-platform-4.5.2.jar:f1d00c167d8921c6e23c626ef9f1c3ae0be473c95c68ffa012bc7ae55a87e2d6',
|
'net.java.dev.jna:jna-platform:5.13.0:jna-platform-5.13.0.jar:474d7b88f6e97009b6ec1d98c3024dd95c23187c65dabfbc35331bcac3d173dd',
|
||||||
'net.java.dev.jna:jna:4.5.2:jna-4.5.2.jar:0c8eb7acf67261656d79005191debaba3b6bf5dd60a43735a245429381dbecff',
|
'net.java.dev.jna:jna:5.13.0:jna-5.13.0.jar:66d4f819a062a51a1d5627bffc23fac55d1677f0e0a1feba144aabdd670a64bb',
|
||||||
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
|
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
|
||||||
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
||||||
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
||||||
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
||||||
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
||||||
'org.briarproject:onionwrapper-core:0.0.2:onionwrapper-core-0.0.2.jar:7038e960c9e59803f0e2c19444dbb5214cd99e5a7463c0a01c45318e07a0eb80',
|
'org.briarproject:onionwrapper-core:0.0.4:onionwrapper-core-0.0.4.jar:28a01a62e96aa763989a8afc325abd3bee54f8021269f91aa48b247a6e717870',
|
||||||
'org.briarproject:onionwrapper-java:0.0.2:onionwrapper-java-0.0.2.jar:87a3f4082174dbbd32c4f5f062b46af1d3fedd8cfa1ec84f6ce6ccb6e3674fb6',
|
'org.briarproject:onionwrapper-java:0.0.4:onionwrapper-java-0.0.4.jar:7806ef878074498653b557e26eb70e6007df3450d6a910a2e9a322f7eb4df442',
|
||||||
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
||||||
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
||||||
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 31
|
targetSdkVersion 33
|
||||||
versionCode 10504
|
versionCode 10504
|
||||||
versionName "1.5.4"
|
versionName "1.5.4"
|
||||||
applicationId "org.briarproject.briar.android"
|
applicationId "org.briarproject.briar.android"
|
||||||
|
|||||||
@@ -19,6 +19,10 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.NEARBY_WIFI_DEVICES"
|
||||||
|
android:usesPermissionFlags="neverForLocation"
|
||||||
|
tools:targetApi="31" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
@@ -30,8 +34,10 @@
|
|||||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
android:maxSdkVersion="18"
|
android:maxSdkVersion="18"
|
||||||
tools:ignore="ScopedStorage" />
|
tools:ignore="ScopedStorage" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
|
||||||
<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION"
|
||||||
|
android:maxSdkVersion="32" />
|
||||||
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
<uses-permission-sdk-23 android:name="android.permission.USE_BIOMETRIC" />
|
<uses-permission-sdk-23 android:name="android.permission.USE_BIOMETRIC" />
|
||||||
<uses-permission-sdk-23 android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission-sdk-23 android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|||||||
@@ -7,17 +7,26 @@ import android.content.IntentFilter;
|
|||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.lifecycle.Service;
|
import org.briarproject.bramble.api.lifecycle.Service;
|
||||||
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
|
||||||
import org.briarproject.briar.api.android.DozeWatchdog;
|
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
import static android.content.Context.POWER_SERVICE;
|
import static android.content.Context.POWER_SERVICE;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
||||||
|
import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED;
|
||||||
|
import static android.os.PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
class DozeWatchdogImpl implements DozeWatchdog, Service {
|
class DozeWatchdogImpl implements DozeWatchdog, Service {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
getLogger(DozeWatchdogImpl.class.getName());
|
||||||
|
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final AtomicBoolean dozed = new AtomicBoolean(false);
|
private final AtomicBoolean dozed = new AtomicBoolean(false);
|
||||||
private final BroadcastReceiver receiver = new DozeBroadcastReceiver();
|
private final BroadcastReceiver receiver = new DozeBroadcastReceiver();
|
||||||
@@ -32,14 +41,18 @@ class DozeWatchdogImpl implements DozeWatchdog, Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startService() throws ServiceException {
|
public void startService() {
|
||||||
if (SDK_INT < 23) return;
|
if (SDK_INT < 23) return;
|
||||||
IntentFilter filter = new IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED);
|
IntentFilter filter = new IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED);
|
||||||
|
if (SDK_INT >= 33) {
|
||||||
|
filter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED);
|
||||||
|
filter.addAction(ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
|
||||||
|
}
|
||||||
appContext.registerReceiver(receiver, filter);
|
appContext.registerReceiver(receiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopService() throws ServiceException {
|
public void stopService() {
|
||||||
if (SDK_INT < 23) return;
|
if (SDK_INT < 23) return;
|
||||||
appContext.unregisterReceiver(receiver);
|
appContext.unregisterReceiver(receiver);
|
||||||
}
|
}
|
||||||
@@ -49,9 +62,33 @@ class DozeWatchdogImpl implements DozeWatchdog, Service {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (SDK_INT < 23) return;
|
if (SDK_INT < 23) return;
|
||||||
|
String action = intent.getAction();
|
||||||
PowerManager pm =
|
PowerManager pm =
|
||||||
(PowerManager) appContext.getSystemService(POWER_SERVICE);
|
(PowerManager) appContext.getSystemService(POWER_SERVICE);
|
||||||
if (pm.isDeviceIdleMode()) dozed.set(true);
|
if (ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
|
||||||
|
if (pm.isDeviceIdleMode()) dozed.set(true);
|
||||||
|
} else if (SDK_INT >= 33) {
|
||||||
|
onReceive33(action, pm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(33)
|
||||||
|
private void onReceive33(String action, PowerManager pm) {
|
||||||
|
if (ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED.equals(action)) {
|
||||||
|
if (pm.isLowPowerStandbyEnabled()) {
|
||||||
|
if (LOG.isLoggable(WARNING)) {
|
||||||
|
LOG.warning("System is in low power standby mode");
|
||||||
|
}
|
||||||
|
dozed.set(true);
|
||||||
|
}
|
||||||
|
} else if (ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED.equals(action)) {
|
||||||
|
if (pm.isDeviceLightIdleMode()) {
|
||||||
|
if (LOG.isLoggable(WARNING)) {
|
||||||
|
LOG.warning("System is in light idle mode");
|
||||||
|
}
|
||||||
|
dozed.set(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.briar.android.account;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -8,6 +9,7 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.account.PowerView.OnCheckedChangedListener;
|
import org.briarproject.briar.android.account.PowerView.OnCheckedChangedListener;
|
||||||
@@ -18,6 +20,7 @@ import androidx.annotation.Nullable;
|
|||||||
|
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
import static org.briarproject.android.dontkillmelib.DozeUtils.getDozeWhitelistingIntent;
|
import static org.briarproject.android.dontkillmelib.DozeUtils.getDozeWhitelistingIntent;
|
||||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
|
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
|
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
|
||||||
@@ -113,7 +116,12 @@ public class DozeFragment extends SetupFragment
|
|||||||
private void askForDozeWhitelisting() {
|
private void askForDozeWhitelisting() {
|
||||||
if (getContext() == null) return;
|
if (getContext() == null) return;
|
||||||
Intent i = getDozeWhitelistingIntent(getContext());
|
Intent i = getDozeWhitelistingIntent(getContext());
|
||||||
startActivityForResult(i, REQUEST_DOZE_WHITELISTING);
|
try {
|
||||||
|
startActivityForResult(i, REQUEST_DOZE_WHITELISTING);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Toast.makeText(requireContext(),
|
||||||
|
R.string.error_start_activity, LENGTH_LONG).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import androidx.annotation.UiThread;
|
|||||||
|
|
||||||
import static org.briarproject.android.dontkillmelib.HuaweiUtils.getHuaweiProtectedAppsIntent;
|
import static org.briarproject.android.dontkillmelib.HuaweiUtils.getHuaweiProtectedAppsIntent;
|
||||||
import static org.briarproject.android.dontkillmelib.HuaweiUtils.protectedAppsNeedsToBeShown;
|
import static org.briarproject.android.dontkillmelib.HuaweiUtils.protectedAppsNeedsToBeShown;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -49,7 +50,7 @@ class HuaweiProtectedAppsView extends PowerView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onButtonClick() {
|
protected void onButtonClick() {
|
||||||
getContext().startActivity(getHuaweiProtectedAppsIntent());
|
tryToStartActivity(getContext(), getHuaweiProtectedAppsIntent());
|
||||||
setChecked(true);
|
setChecked(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,17 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.POST_NOTIFICATIONS;
|
||||||
import static android.content.Context.INPUT_METHOD_SERVICE;
|
import static android.content.Context.INPUT_METHOD_SERVICE;
|
||||||
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
||||||
|
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
||||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
|
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.setError;
|
import static org.briarproject.briar.android.util.UiUtils.setError;
|
||||||
|
|
||||||
@@ -38,6 +45,10 @@ public class SetPasswordFragment extends SetupFragment {
|
|||||||
private StrengthMeter strengthMeter;
|
private StrengthMeter strengthMeter;
|
||||||
private Button nextButton;
|
private Button nextButton;
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<String> requestPermissionLauncher =
|
||||||
|
registerForActivityResult(new RequestPermission(), isGranted ->
|
||||||
|
setPassword());
|
||||||
|
|
||||||
public static SetPasswordFragment newInstance() {
|
public static SetPasswordFragment newInstance() {
|
||||||
return new SetPasswordFragment();
|
return new SetPasswordFragment();
|
||||||
}
|
}
|
||||||
@@ -121,6 +132,18 @@ public class SetPasswordFragment extends SetupFragment {
|
|||||||
IBinder token = passwordEntry.getWindowToken();
|
IBinder token = passwordEntry.getWindowToken();
|
||||||
Object o = requireContext().getSystemService(INPUT_METHOD_SERVICE);
|
Object o = requireContext().getSystemService(INPUT_METHOD_SERVICE);
|
||||||
((InputMethodManager) o).hideSoftInputFromWindow(token, 0);
|
((InputMethodManager) o).hideSoftInputFromWindow(token, 0);
|
||||||
|
if (SDK_INT >= 33 &&
|
||||||
|
checkSelfPermission(requireContext(), POST_NOTIFICATIONS) !=
|
||||||
|
PERMISSION_GRANTED) {
|
||||||
|
// this calls setPassword() when it returns
|
||||||
|
requestPermissionLauncher.launch(POST_NOTIFICATIONS);
|
||||||
|
} else {
|
||||||
|
setPassword();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPassword() {
|
||||||
viewModel.setPassword(passwordEntry.getText().toString());
|
viewModel.setPassword(passwordEntry.getText().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class SetupActivity extends BaseActivity
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ViewModelProvider.Factory viewModelFactory;
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
SetupViewModel viewModel;
|
private SetupViewModel viewModel;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
@@ -71,16 +71,16 @@ public class SetupActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void showPasswordFragment() {
|
private void showPasswordFragment() {
|
||||||
showNextFragment(SetPasswordFragment.newInstance());
|
showNextFragment(SetPasswordFragment.newInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(23)
|
@TargetApi(23)
|
||||||
void showDozeFragment() {
|
private void showDozeFragment() {
|
||||||
showNextFragment(DozeFragment.newInstance());
|
showNextFragment(DozeFragment.newInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
void showApp() {
|
private void showApp() {
|
||||||
Intent i = new Intent(this, ENTRY_ACTIVITY);
|
Intent i = new Intent(this, ENTRY_ACTIVITY);
|
||||||
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME |
|
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME |
|
||||||
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_CLEAR_TOP);
|
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.briar.android.account;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
import android.app.KeyguardManager;
|
import android.app.KeyguardManager;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.hardware.biometrics.BiometricPrompt;
|
import android.hardware.biometrics.BiometricPrompt;
|
||||||
import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback;
|
import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback;
|
||||||
@@ -28,6 +29,7 @@ import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_CANCEL
|
|||||||
import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED;
|
import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_KEYGUARD_UNLOCK;
|
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_KEYGUARD_UNLOCK;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.hasKeyguardLock;
|
import static org.briarproject.briar.android.util.UiUtils.hasKeyguardLock;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.hasUsableFingerprint;
|
import static org.briarproject.briar.android.util.UiUtils.hasUsableFingerprint;
|
||||||
@@ -191,7 +193,12 @@ public class UnlockActivity extends BaseActivity {
|
|||||||
unlock();
|
unlock();
|
||||||
} else {
|
} else {
|
||||||
keyguardShown = true;
|
keyguardShown = true;
|
||||||
startActivityForResult(intent, REQUEST_KEYGUARD_UNLOCK);
|
try {
|
||||||
|
startActivityForResult(intent, REQUEST_KEYGUARD_UNLOCK);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Toast.makeText(this, R.string.error_start_activity, LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
overridePendingTransition(0, 0);
|
overridePendingTransition(0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.briar.android.account;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@@ -60,12 +61,12 @@ class XiaomiLockAppsView extends PowerView {
|
|||||||
getContext().startActivity(getXiaomiLockAppsIntent());
|
getContext().startActivity(getXiaomiLockAppsIntent());
|
||||||
setChecked(true);
|
setChecked(true);
|
||||||
return;
|
return;
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException | ActivityNotFoundException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
|
Toast.makeText(getContext(),
|
||||||
|
R.string.dnkm_xiaomi_lock_apps_error_toast,
|
||||||
|
LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
Toast.makeText(getContext(),
|
|
||||||
R.string.dnkm_xiaomi_lock_apps_error_toast,
|
|
||||||
LENGTH_LONG).show();
|
|
||||||
// Let the user continue with setup
|
// Let the user continue with setup
|
||||||
setChecked(true);
|
setChecked(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package org.briarproject.briar.android.activity;
|
package org.briarproject.briar.android.activity;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.transition.Transition;
|
import android.transition.Transition;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
|
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
|
||||||
import org.briarproject.bramble.api.system.Wakeful;
|
import org.briarproject.bramble.api.system.Wakeful;
|
||||||
@@ -34,9 +36,12 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
|
|||||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
|
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.android.dontkillmelib.DozeUtils.getDozeWhitelistingIntent;
|
import static org.briarproject.android.dontkillmelib.DozeUtils.getDozeWhitelistingIntent;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
|
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
|
||||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD;
|
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD;
|
||||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_UNLOCK;
|
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_UNLOCK;
|
||||||
@@ -179,7 +184,13 @@ public abstract class BriarActivity extends BaseActivity {
|
|||||||
b.setPositiveButton(R.string.fix,
|
b.setPositiveButton(R.string.fix,
|
||||||
(dialog, which) -> {
|
(dialog, which) -> {
|
||||||
Intent i = getDozeWhitelistingIntent(BriarActivity.this);
|
Intent i = getDozeWhitelistingIntent(BriarActivity.this);
|
||||||
startActivityForResult(i, REQUEST_DOZE_WHITELISTING);
|
try {
|
||||||
|
startActivityForResult(i, REQUEST_DOZE_WHITELISTING);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
Toast.makeText(this, R.string.error_start_activity,
|
||||||
|
LENGTH_LONG).show();
|
||||||
|
}
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
});
|
});
|
||||||
b.setNegativeButton(R.string.cancel,
|
b.setNegativeButton(R.string.cancel,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
|||||||
import org.briarproject.briar.api.android.ScreenFilterMonitor.AppDetails;
|
import org.briarproject.briar.api.android.ScreenFilterMonitor.AppDetails;
|
||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -32,6 +33,7 @@ import androidx.fragment.app.DialogFragment;
|
|||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION;
|
import static android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION;
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -68,6 +70,7 @@ public class ScreenFilterDialogFragment extends DialogFragment {
|
|||||||
((BaseActivity) requireActivity()).getActivityComponent().inject(this);
|
((BaseActivity) requireActivity()).getActivityComponent().inject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
Activity activity = getActivity();
|
Activity activity = getActivity();
|
||||||
@@ -98,7 +101,7 @@ public class ScreenFilterDialogFragment extends DialogFragment {
|
|||||||
builder.setNeutralButton(R.string.screen_filter_review_apps,
|
builder.setNeutralButton(R.string.screen_filter_review_apps,
|
||||||
(dialog, which) -> {
|
(dialog, which) -> {
|
||||||
Intent i = new Intent(ACTION_MANAGE_OVERLAY_PERMISSION);
|
Intent i = new Intent(ACTION_MANAGE_OVERLAY_PERMISSION);
|
||||||
startActivity(i);
|
tryToStartActivity(requireActivity(), i);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
builder.setPositiveButton(R.string.continue_button, (dialog, which) -> {
|
builder.setPositiveButton(R.string.continue_button, (dialog, which) -> {
|
||||||
|
|||||||
@@ -1,21 +1,27 @@
|
|||||||
package org.briarproject.briar.android.hotspot;
|
package org.briarproject.briar.android.hotspot;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
import static android.content.Context.WIFI_SERVICE;
|
import static android.content.Context.WIFI_SERVICE;
|
||||||
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for the ConditionManagers that ensure that the conditions
|
* Abstract base class for the ConditionManagers that ensure that the conditions
|
||||||
* to open a hotspot are fulfilled. There are different extensions of this for
|
* to open a hotspot are fulfilled. There are different extensions of this for
|
||||||
* API levels lower than 29 and 29+.
|
* API levels lower than 29, 29+ and 33+.
|
||||||
*/
|
*/
|
||||||
abstract class AbstractConditionManager {
|
abstract class AbstractConditionManager {
|
||||||
|
|
||||||
@@ -28,6 +34,7 @@ abstract class AbstractConditionManager {
|
|||||||
final Consumer<Boolean> permissionUpdateCallback;
|
final Consumer<Boolean> permissionUpdateCallback;
|
||||||
protected FragmentActivity ctx;
|
protected FragmentActivity ctx;
|
||||||
WifiManager wifiManager;
|
WifiManager wifiManager;
|
||||||
|
private ActivityResultLauncher<Intent> wifiRequest;
|
||||||
|
|
||||||
AbstractConditionManager(Consumer<Boolean> permissionUpdateCallback) {
|
AbstractConditionManager(Consumer<Boolean> permissionUpdateCallback) {
|
||||||
this.permissionUpdateCallback = permissionUpdateCallback;
|
this.permissionUpdateCallback = permissionUpdateCallback;
|
||||||
@@ -38,8 +45,12 @@ abstract class AbstractConditionManager {
|
|||||||
*/
|
*/
|
||||||
void init(FragmentActivity ctx) {
|
void init(FragmentActivity ctx) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.wifiManager = (WifiManager) ctx.getApplicationContext()
|
wifiManager = (WifiManager) ctx.getApplicationContext()
|
||||||
.getSystemService(WIFI_SERVICE);
|
.getSystemService(WIFI_SERVICE);
|
||||||
|
wifiRequest = ctx.registerForActivityResult(
|
||||||
|
new ActivityResultContracts.StartActivityForResult(),
|
||||||
|
result -> permissionUpdateCallback
|
||||||
|
.accept(wifiManager.isWifiEnabled()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,6 +68,8 @@ abstract class AbstractConditionManager {
|
|||||||
*/
|
*/
|
||||||
abstract boolean checkAndRequestConditions();
|
abstract boolean checkAndRequestConditions();
|
||||||
|
|
||||||
|
abstract String getWifiSettingsAction();
|
||||||
|
|
||||||
void showRationale(Context ctx, @StringRes int title,
|
void showRationale(Context ctx, @StringRes int title,
|
||||||
@StringRes int body, Runnable onContinueClicked,
|
@StringRes int body, Runnable onContinueClicked,
|
||||||
Runnable onDismiss) {
|
Runnable onDismiss) {
|
||||||
@@ -69,4 +82,13 @@ abstract class AbstractConditionManager {
|
|||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void requestEnableWiFi() {
|
||||||
|
try {
|
||||||
|
wifiRequest.launch(new Intent(getWifiSettingsAction()));
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
package org.briarproject.briar.android.hotspot;
|
package org.briarproject.briar.android.hotspot;
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultCaller;
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
|
||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
@@ -22,20 +19,14 @@ import static java.util.logging.Logger.getLogger;
|
|||||||
* As soon as {@link #checkAndRequestConditions()} returns true,
|
* As soon as {@link #checkAndRequestConditions()} returns true,
|
||||||
* all conditions are fulfilled.
|
* all conditions are fulfilled.
|
||||||
*/
|
*/
|
||||||
|
@NotNullByDefault
|
||||||
class ConditionManager extends AbstractConditionManager {
|
class ConditionManager extends AbstractConditionManager {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(ConditionManager.class.getName());
|
getLogger(ConditionManager.class.getName());
|
||||||
|
|
||||||
private final ActivityResultLauncher<Intent> wifiRequest;
|
ConditionManager(Consumer<Boolean> permissionUpdateCallback) {
|
||||||
|
super( permissionUpdateCallback);
|
||||||
ConditionManager(ActivityResultCaller arc,
|
|
||||||
Consumer<Boolean> permissionUpdateCallback) {
|
|
||||||
super(permissionUpdateCallback);
|
|
||||||
wifiRequest = arc.registerForActivityResult(
|
|
||||||
new StartActivityForResult(),
|
|
||||||
result -> permissionUpdateCallback
|
|
||||||
.accept(wifiManager.isWifiEnabled()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -76,8 +67,9 @@ class ConditionManager extends AbstractConditionManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requestEnableWiFi() {
|
@Override
|
||||||
wifiRequest.launch(new Intent(Settings.ACTION_WIFI_SETTINGS));
|
String getWifiSettingsAction() {
|
||||||
|
return Settings.ACTION_WIFI_SETTINGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
package org.briarproject.briar.android.hotspot;
|
package org.briarproject.briar.android.hotspot;
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.util.Permission;
|
import org.briarproject.briar.android.util.Permission;
|
||||||
import org.briarproject.briar.android.util.PermissionUtils;
|
import org.briarproject.briar.android.util.PermissionUtils;
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultCaller;
|
import androidx.activity.result.ActivityResultCaller;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
|
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
@@ -28,12 +27,13 @@ import static org.briarproject.briar.android.util.PermissionUtils.showLocationDi
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This class ensures that the conditions to open a hotspot are fulfilled on
|
* This class ensures that the conditions to open a hotspot are fulfilled on
|
||||||
* API levels >= 29.
|
* API levels >= 29 and < 33.
|
||||||
* <p>
|
* <p>
|
||||||
* As soon as {@link #checkAndRequestConditions()} returns true,
|
* As soon as {@link #checkAndRequestConditions()} returns true,
|
||||||
* all conditions are fulfilled.
|
* all conditions are fulfilled.
|
||||||
*/
|
*/
|
||||||
@RequiresApi(29)
|
@RequiresApi(29)
|
||||||
|
@NotNullByDefault
|
||||||
class ConditionManager29 extends AbstractConditionManager {
|
class ConditionManager29 extends AbstractConditionManager {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
@@ -42,7 +42,6 @@ class ConditionManager29 extends AbstractConditionManager {
|
|||||||
private Permission locationPermission = Permission.UNKNOWN;
|
private Permission locationPermission = Permission.UNKNOWN;
|
||||||
|
|
||||||
private final ActivityResultLauncher<String> locationRequest;
|
private final ActivityResultLauncher<String> locationRequest;
|
||||||
private final ActivityResultLauncher<Intent> wifiRequest;
|
|
||||||
|
|
||||||
ConditionManager29(ActivityResultCaller arc,
|
ConditionManager29(ActivityResultCaller arc,
|
||||||
Consumer<Boolean> permissionUpdateCallback) {
|
Consumer<Boolean> permissionUpdateCallback) {
|
||||||
@@ -53,11 +52,6 @@ class ConditionManager29 extends AbstractConditionManager {
|
|||||||
onRequestPermissionResult(granted);
|
onRequestPermissionResult(granted);
|
||||||
permissionUpdateCallback.accept(TRUE.equals(granted));
|
permissionUpdateCallback.accept(TRUE.equals(granted));
|
||||||
});
|
});
|
||||||
wifiRequest = arc.registerForActivityResult(
|
|
||||||
new StartActivityForResult(),
|
|
||||||
result -> permissionUpdateCallback
|
|
||||||
.accept(wifiManager.isWifiEnabled())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -131,6 +125,11 @@ class ConditionManager29 extends AbstractConditionManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getWifiSettingsAction() {
|
||||||
|
return Settings.Panel.ACTION_WIFI;
|
||||||
|
}
|
||||||
|
|
||||||
private void onRequestPermissionResult(@Nullable Boolean granted) {
|
private void onRequestPermissionResult(@Nullable Boolean granted) {
|
||||||
if (granted != null && granted) {
|
if (granted != null && granted) {
|
||||||
locationPermission = Permission.GRANTED;
|
locationPermission = Permission.GRANTED;
|
||||||
@@ -146,8 +145,4 @@ class ConditionManager29 extends AbstractConditionManager {
|
|||||||
locationRequest.launch(ACCESS_FINE_LOCATION);
|
locationRequest.launch(ACCESS_FINE_LOCATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requestEnableWiFi() {
|
|
||||||
wifiRequest.launch(new Intent(Settings.Panel.ACTION_WIFI));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package org.briarproject.briar.android.hotspot;
|
||||||
|
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.util.Permission;
|
||||||
|
import org.briarproject.briar.android.util.PermissionUtils;
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultCaller;
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
import androidx.core.util.Consumer;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.NEARBY_WIFI_DEVICES;
|
||||||
|
import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale;
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class ensures that the conditions to open a hotspot are fulfilled on
|
||||||
|
* API levels >= 33.
|
||||||
|
* <p>
|
||||||
|
* As soon as {@link #checkAndRequestConditions()} returns true,
|
||||||
|
* all conditions are fulfilled.
|
||||||
|
*/
|
||||||
|
@RequiresApi(33)
|
||||||
|
@NotNullByDefault
|
||||||
|
class ConditionManager33 extends AbstractConditionManager {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
getLogger(ConditionManager33.class.getName());
|
||||||
|
|
||||||
|
private Permission nearbyWifiPermission = Permission.UNKNOWN;
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<String> nearbyWifiRequest;
|
||||||
|
|
||||||
|
ConditionManager33(ActivityResultCaller arc,
|
||||||
|
Consumer<Boolean> permissionUpdateCallback) {
|
||||||
|
super(permissionUpdateCallback);
|
||||||
|
// permissionUpdateCallback receives false if permissions were denied
|
||||||
|
nearbyWifiRequest = arc.registerForActivityResult(
|
||||||
|
new RequestPermission(), granted -> {
|
||||||
|
onRequestPermissionResult(granted);
|
||||||
|
permissionUpdateCallback.accept(TRUE.equals(granted));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void onStart() {
|
||||||
|
nearbyWifiPermission = Permission.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean areEssentialPermissionsGranted() {
|
||||||
|
boolean isWifiEnabled = wifiManager.isWifiEnabled();
|
||||||
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info(String.format("areEssentialPermissionsGranted(): " +
|
||||||
|
"nearbyWifiPermission? %s, " +
|
||||||
|
"wifiManager.isWifiEnabled()? %b",
|
||||||
|
nearbyWifiPermission, isWifiEnabled));
|
||||||
|
}
|
||||||
|
return nearbyWifiPermission == Permission.GRANTED && isWifiEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean checkAndRequestConditions() {
|
||||||
|
if (areEssentialPermissionsGranted()) return true;
|
||||||
|
|
||||||
|
if (nearbyWifiPermission == Permission.UNKNOWN) {
|
||||||
|
requestPermissions();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the location permission has been permanently denied, ask the
|
||||||
|
// user to change the setting
|
||||||
|
if (nearbyWifiPermission == Permission.PERMANENTLY_DENIED) {
|
||||||
|
PermissionUtils.showDenialDialog(ctx,
|
||||||
|
R.string.permission_nearby_devices_title,
|
||||||
|
R.string.permission_hotspot_nearby_wifi_denied_body,
|
||||||
|
() -> permissionUpdateCallback.accept(false));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should we show the rationale for location permission?
|
||||||
|
if (nearbyWifiPermission == Permission.SHOW_RATIONALE) {
|
||||||
|
showRationale(ctx,
|
||||||
|
R.string.permission_location_title,
|
||||||
|
R.string.permission_hotspot_nearby_wifi_request_body,
|
||||||
|
this::requestPermissions,
|
||||||
|
() -> permissionUpdateCallback.accept(false));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If Wifi is not enabled, we show the rationale for enabling Wifi?
|
||||||
|
if (!wifiManager.isWifiEnabled()) {
|
||||||
|
showRationale(ctx, R.string.wifi_settings_title,
|
||||||
|
R.string.wifi_settings_request_enable_body,
|
||||||
|
this::requestEnableWiFi,
|
||||||
|
() -> permissionUpdateCallback.accept(false));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we shouldn't usually reach this point, but if we do, return false
|
||||||
|
// anyway to force a recheck. Maybe some condition changed in the
|
||||||
|
// meantime.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getWifiSettingsAction() {
|
||||||
|
return Settings.Panel.ACTION_WIFI;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onRequestPermissionResult(@Nullable Boolean granted) {
|
||||||
|
if (granted != null && granted) {
|
||||||
|
nearbyWifiPermission = Permission.GRANTED;
|
||||||
|
} else if (shouldShowRequestPermissionRationale(ctx,
|
||||||
|
NEARBY_WIFI_DEVICES)) {
|
||||||
|
nearbyWifiPermission = Permission.SHOW_RATIONALE;
|
||||||
|
} else {
|
||||||
|
nearbyWifiPermission = Permission.PERMANENTLY_DENIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestPermissions() {
|
||||||
|
nearbyWifiRequest.launch(NEARBY_WIFI_DEVICES);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ import static android.view.View.VISIBLE;
|
|||||||
import static androidx.transition.TransitionManager.beginDelayedTransition;
|
import static androidx.transition.TransitionManager.beginDelayedTransition;
|
||||||
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
import static org.briarproject.briar.android.hotspot.HotspotViewModel.getApkFileName;
|
import static org.briarproject.briar.android.hotspot.HotspotViewModel.getApkFileName;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -102,7 +103,7 @@ public class FallbackFragment extends BaseFragment {
|
|||||||
i.putExtra(EXTRA_STREAM, uri);
|
i.putExtra(EXTRA_STREAM, uri);
|
||||||
i.setType("*/*"); // gives us all sharing options
|
i.setType("*/*"); // gives us all sharing options
|
||||||
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
startActivity(Intent.createChooser(i, null));
|
tryToStartActivity(requireActivity(), Intent.createChooser(i, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,10 @@ public class HotspotIntroFragment extends Fragment {
|
|||||||
private TextView progressTextView;
|
private TextView progressTextView;
|
||||||
|
|
||||||
private final AbstractConditionManager conditionManager = SDK_INT < 29 ?
|
private final AbstractConditionManager conditionManager = SDK_INT < 29 ?
|
||||||
new ConditionManager(this, this::onPermissionUpdate) :
|
new ConditionManager(this::onPermissionUpdate) :
|
||||||
new ConditionManager29(this, this::onPermissionUpdate);
|
SDK_INT >= 33 ?
|
||||||
|
new ConditionManager33(this, this::onPermissionUpdate) :
|
||||||
|
new ConditionManager29(this, this::onPermissionUpdate);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
@@ -87,7 +89,6 @@ public class HotspotIntroFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onButtonClick(View view) {
|
private void onButtonClick(View view) {
|
||||||
startButton.setEnabled(false);
|
|
||||||
startHotspotIfConditionsFulfilled();
|
startHotspotIfConditionsFulfilled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,13 +22,19 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.POST_NOTIFICATIONS;
|
||||||
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
||||||
|
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
||||||
import static org.briarproject.bramble.api.crypto.DecryptionResult.KEY_STRENGTHENER_ERROR;
|
import static org.briarproject.bramble.api.crypto.DecryptionResult.KEY_STRENGTHENER_ERROR;
|
||||||
import static org.briarproject.bramble.api.crypto.DecryptionResult.SUCCESS;
|
import static org.briarproject.bramble.api.crypto.DecryptionResult.SUCCESS;
|
||||||
import static org.briarproject.briar.android.login.LoginUtils.createKeyStrengthenerErrorDialog;
|
import static org.briarproject.briar.android.login.LoginUtils.createKeyStrengthenerErrorDialog;
|
||||||
@@ -52,6 +58,10 @@ public class PasswordFragment extends BaseFragment implements TextWatcher {
|
|||||||
private TextInputLayout input;
|
private TextInputLayout input;
|
||||||
private TextInputEditText password;
|
private TextInputEditText password;
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<String> requestPermissionLauncher =
|
||||||
|
registerForActivityResult(new RequestPermission(), isGranted ->
|
||||||
|
validatePassword());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectFragment(ActivityComponent component) {
|
public void injectFragment(ActivityComponent component) {
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
@@ -109,6 +119,17 @@ public class PasswordFragment extends BaseFragment implements TextWatcher {
|
|||||||
hideSoftKeyboard(password);
|
hideSoftKeyboard(password);
|
||||||
signInButton.setVisibility(INVISIBLE);
|
signInButton.setVisibility(INVISIBLE);
|
||||||
progress.setVisibility(VISIBLE);
|
progress.setVisibility(VISIBLE);
|
||||||
|
if (SDK_INT >= 33 &&
|
||||||
|
checkSelfPermission(requireContext(), POST_NOTIFICATIONS) !=
|
||||||
|
PERMISSION_GRANTED) {
|
||||||
|
// this calls validatePassword() when it returns
|
||||||
|
requestPermissionLauncher.launch(POST_NOTIFICATIONS);
|
||||||
|
} else {
|
||||||
|
validatePassword();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validatePassword() {
|
||||||
viewModel.validatePassword(password.getText().toString());
|
viewModel.validatePassword(password.getText().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.briar.android.reporting;
|
package org.briarproject.briar.android.reporting;
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -33,13 +32,11 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static android.widget.Toast.LENGTH_LONG;
|
|
||||||
import static android.widget.Toast.LENGTH_SHORT;
|
import static android.widget.Toast.LENGTH_SHORT;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
|
||||||
import static org.briarproject.briar.android.util.UiUtils.onSingleLinkClick;
|
import static org.briarproject.briar.android.util.UiUtils.onSingleLinkClick;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -180,13 +177,7 @@ public class ReportFormFragment extends BaseFragment {
|
|||||||
private void triggerPrivacyPolicy() {
|
private void triggerPrivacyPolicy() {
|
||||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||||
i.setData(Uri.parse("https://briarproject.org/privacy-policy/\\"));
|
i.setData(Uri.parse("https://briarproject.org/privacy-policy/\\"));
|
||||||
try {
|
tryToStartActivity(requireActivity(), i);
|
||||||
startActivity(i);
|
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
Toast.makeText(requireContext(),
|
|
||||||
R.string.error_start_activity, LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.briar.android.settings;
|
package org.briarproject.briar.android.settings;
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -8,7 +7,6 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.briarproject.briar.BuildConfig;
|
import org.briarproject.briar.BuildConfig;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
@@ -21,10 +19,9 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import static android.widget.Toast.LENGTH_LONG;
|
import static android.content.Intent.ACTION_VIEW;
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -85,16 +82,9 @@ public class AboutFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void goToUrl(String url) {
|
private void goToUrl(String url) {
|
||||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
Intent i = new Intent(ACTION_VIEW);
|
||||||
i.setData(Uri.parse(url));
|
i.setData(Uri.parse(url));
|
||||||
try {
|
tryToStartActivity(requireActivity(), i);
|
||||||
startActivity(i);
|
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
Toast.makeText(requireContext(),
|
|
||||||
R.string.error_start_activity, LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
package org.briarproject.briar.android.settings;
|
package org.briarproject.briar.android.settings;
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.mailbox.MailboxActivity;
|
import org.briarproject.briar.android.mailbox.MailboxActivity;
|
||||||
@@ -28,12 +26,12 @@ import androidx.preference.PreferenceGroup;
|
|||||||
|
|
||||||
import static android.content.Intent.ACTION_SEND;
|
import static android.content.Intent.ACTION_SEND;
|
||||||
import static android.content.Intent.EXTRA_TEXT;
|
import static android.content.Intent.EXTRA_TEXT;
|
||||||
import static android.widget.Toast.LENGTH_LONG;
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile;
|
import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.triggerFeedback;
|
import static org.briarproject.briar.android.util.UiUtils.triggerFeedback;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -101,12 +99,8 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||||||
Intent sendIntent = new Intent(ACTION_SEND);
|
Intent sendIntent = new Intent(ACTION_SEND);
|
||||||
sendIntent.putExtra(EXTRA_TEXT, text);
|
sendIntent.putExtra(EXTRA_TEXT, text);
|
||||||
sendIntent.setType("text/plain");
|
sendIntent.setType("text/plain");
|
||||||
try {
|
tryToStartActivity(requireActivity(),
|
||||||
startActivity(Intent.createChooser(sendIntent, null));
|
Intent.createChooser(sendIntent, null));
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
Toast.makeText(requireContext(),
|
|
||||||
R.string.error_start_activity, LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
Preference prefFeedback =
|
Preference prefFeedback =
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package org.briarproject.briar.android.util;
|
package org.briarproject.briar.android.util;
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
||||||
@@ -29,10 +27,10 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
|||||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS;
|
import static android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS;
|
||||||
import static android.widget.Toast.LENGTH_LONG;
|
|
||||||
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
|
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.tryToStartActivity;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -47,7 +45,7 @@ public class PermissionUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPermissionGranted(Context ctx, String permission) {
|
private static boolean isPermissionGranted(Context ctx, String permission) {
|
||||||
return checkSelfPermission(ctx, permission) ==
|
return checkSelfPermission(ctx, permission) ==
|
||||||
PERMISSION_GRANTED;
|
PERMISSION_GRANTED;
|
||||||
}
|
}
|
||||||
@@ -68,7 +66,7 @@ public class PermissionUtils {
|
|||||||
gotPermission(ctx, grantedMap, BLUETOOTH_SCAN);
|
gotPermission(ctx, grantedMap, BLUETOOTH_SCAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DialogInterface.OnClickListener getGoToSettingsListener(
|
private static DialogInterface.OnClickListener getGoToSettingsListener(
|
||||||
Context context) {
|
Context context) {
|
||||||
return (dialog, which) -> {
|
return (dialog, which) -> {
|
||||||
Intent i = new Intent();
|
Intent i = new Intent();
|
||||||
@@ -76,7 +74,7 @@ public class PermissionUtils {
|
|||||||
i.addCategory(CATEGORY_DEFAULT);
|
i.addCategory(CATEGORY_DEFAULT);
|
||||||
i.setData(Uri.parse("package:" + APPLICATION_ID));
|
i.setData(Uri.parse("package:" + APPLICATION_ID));
|
||||||
i.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
i.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||||
context.startActivity(i);
|
tryToStartActivity(context, i);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,12 +121,7 @@ public class PermissionUtils {
|
|||||||
builder.setPositiveButton(R.string.permission_location_setting_button,
|
builder.setPositiveButton(R.string.permission_location_setting_button,
|
||||||
(dialog, which) -> {
|
(dialog, which) -> {
|
||||||
Intent i = new Intent(ACTION_LOCATION_SOURCE_SETTINGS);
|
Intent i = new Intent(ACTION_LOCATION_SOURCE_SETTINGS);
|
||||||
try {
|
tryToStartActivity(ctx, i);
|
||||||
ctx.startActivity(i);
|
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
Toast.makeText(ctx, R.string.error_start_activity,
|
|
||||||
LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,6 +157,15 @@ public class UiUtils {
|
|||||||
ta.commit();
|
ta.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void tryToStartActivity(Context ctx, Intent intent) {
|
||||||
|
try {
|
||||||
|
ctx.startActivity(intent);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static String getContactDisplayName(Author author,
|
public static String getContactDisplayName(Author author,
|
||||||
@Nullable String alias) {
|
@Nullable String alias) {
|
||||||
String name = author.getName();
|
String name = author.getName();
|
||||||
|
|||||||
@@ -13,10 +13,10 @@
|
|||||||
android:layout_margin="@dimen/margin_medium"
|
android:layout_margin="@dimen/margin_medium"
|
||||||
android:contentDescription="@string/info"
|
android:contentDescription="@string/info"
|
||||||
android:drawablePadding="@dimen/margin_medium"
|
android:drawablePadding="@dimen/margin_medium"
|
||||||
android:drawableTint="?attr/colorControlNormal"
|
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
app:drawableLeftCompat="@drawable/ic_info_dark"
|
app:drawableLeftCompat="@drawable/ic_info_dark"
|
||||||
app:drawableStartCompat="@drawable/ic_info_dark"
|
app:drawableStartCompat="@drawable/ic_info_dark"
|
||||||
|
app:drawableTint="?attr/colorControlNormal"
|
||||||
tools:text="Did you know that if you took all the veins out of your body and laid them out end to end, you would die?" />
|
tools:text="Did you know that if you took all the veins out of your body and laid them out end to end, you would die?" />
|
||||||
|
|
||||||
</merge>
|
</merge>
|
||||||
@@ -789,6 +789,7 @@
|
|||||||
<string name="permission_camera_title">Camera permission</string>
|
<string name="permission_camera_title">Camera permission</string>
|
||||||
<string name="permission_camera_request_body">To scan the QR code, Briar needs access to the camera.</string>
|
<string name="permission_camera_request_body">To scan the QR code, Briar needs access to the camera.</string>
|
||||||
<string name="permission_location_title">Location permission</string>
|
<string name="permission_location_title">Location permission</string>
|
||||||
|
<string name="permission_nearby_devices_title">Nearby devices permission</string>
|
||||||
<string name="permission_location_request_body">To discover Bluetooth devices, Briar needs permission to access your location.\n\nBriar does not store your location or share it with anyone.</string>
|
<string name="permission_location_request_body">To discover Bluetooth devices, Briar needs permission to access your location.\n\nBriar does not store your location or share it with anyone.</string>
|
||||||
<string name="permission_camera_location_title">Camera and location</string>
|
<string name="permission_camera_location_title">Camera and location</string>
|
||||||
<string name="permission_camera_location_request_body">To scan the QR code, Briar needs access to the camera.\n\nTo discover Bluetooth devices, Briar needs permission to access your location.\n\nBriar does not store your location or share it with anyone.</string>
|
<string name="permission_camera_location_request_body">To scan the QR code, Briar needs access to the camera.\n\nTo discover Bluetooth devices, Briar needs permission to access your location.\n\nBriar does not store your location or share it with anyone.</string>
|
||||||
@@ -833,6 +834,8 @@
|
|||||||
<string name="permission_hotspot_location_request_precise_body">To create a Wi-Fi hotspot, Briar needs permission to access your precise location.\n\nBriar does not store your location or share it with anyone.</string>
|
<string name="permission_hotspot_location_request_precise_body">To create a Wi-Fi hotspot, Briar needs permission to access your precise location.\n\nBriar does not store your location or share it with anyone.</string>
|
||||||
<string name="permission_hotspot_location_denied_body">You have denied access to your location, but Briar needs this permission to create a Wi-Fi hotspot.\n\nPlease consider granting access.</string>
|
<string name="permission_hotspot_location_denied_body">You have denied access to your location, but Briar needs this permission to create a Wi-Fi hotspot.\n\nPlease consider granting access.</string>
|
||||||
<string name="permission_hotspot_location_denied_precise_body">You have denied access to your precise location, but Briar needs this permission to create a Wi-Fi hotspot.\n\nPlease consider granting access.</string>
|
<string name="permission_hotspot_location_denied_precise_body">You have denied access to your precise location, but Briar needs this permission to create a Wi-Fi hotspot.\n\nPlease consider granting access.</string>
|
||||||
|
<string name="permission_hotspot_nearby_wifi_request_body">To create a Wi-Fi hotspot, Briar needs permission to access nearby devices.</string>
|
||||||
|
<string name="permission_hotspot_nearby_wifi_denied_body">You have denied access to nearby devices, but Briar needs this permission to create a Wi-Fi hotspot.\n\nPlease consider granting access.</string>
|
||||||
<string name="wifi_settings_title">Wi-Fi setting</string>
|
<string name="wifi_settings_title">Wi-Fi setting</string>
|
||||||
<string name="wifi_settings_request_enable_body">To create a Wi-Fi hotspot, Briar needs to use Wi-Fi. Please enable it.</string>
|
<string name="wifi_settings_request_enable_body">To create a Wi-Fi hotspot, Briar needs to use Wi-Fi. Please enable it.</string>
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,13 @@ public interface BlogManager {
|
|||||||
@Nullable String comment, BlogPostHeader parentHeader)
|
@Nullable String comment, BlogPostHeader parentHeader)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a comment to an existing blog post or reblogs it.
|
||||||
|
*/
|
||||||
|
void addLocalComment(Transaction txn, LocalAuthor author,
|
||||||
|
GroupId groupId, @Nullable String comment,
|
||||||
|
BlogPostHeader parentHeader) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the blog with the given ID.
|
* Returns the blog with the given ID.
|
||||||
*/
|
*/
|
||||||
@@ -99,6 +106,11 @@ public interface BlogManager {
|
|||||||
*/
|
*/
|
||||||
Collection<Blog> getBlogs() throws DbException;
|
Collection<Blog> getBlogs() throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all blogs to which the user subscribes.
|
||||||
|
*/
|
||||||
|
Collection<Blog> getBlogs(Transaction txn) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the group IDs of all blogs to which the user subscribes.
|
* Returns the group IDs of all blogs to which the user subscribes.
|
||||||
*/
|
*/
|
||||||
@@ -136,6 +148,11 @@ public interface BlogManager {
|
|||||||
*/
|
*/
|
||||||
void setReadFlag(MessageId m, boolean read) throws DbException;
|
void setReadFlag(MessageId m, boolean read) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a blog post as read or unread.
|
||||||
|
*/
|
||||||
|
void setReadFlag(Transaction txn, MessageId m, boolean read) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a hook to be called whenever a blog is removed.
|
* Registers a hook to be called whenever a blog is removed.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -257,12 +257,19 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
|
|||||||
public void addLocalComment(LocalAuthor author, GroupId groupId,
|
public void addLocalComment(LocalAuthor author, GroupId groupId,
|
||||||
@Nullable String comment, BlogPostHeader parentHeader)
|
@Nullable String comment, BlogPostHeader parentHeader)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
db.transaction(false, txn -> {
|
||||||
|
addLocalComment(txn, author, groupId, comment, parentHeader);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addLocalComment(Transaction txn, LocalAuthor author,
|
||||||
|
GroupId groupId, @Nullable String comment,
|
||||||
|
BlogPostHeader parentHeader) throws DbException {
|
||||||
MessageType type = parentHeader.getType();
|
MessageType type = parentHeader.getType();
|
||||||
if (type != POST && type != COMMENT)
|
if (type != POST && type != COMMENT)
|
||||||
throw new IllegalArgumentException("Comment on unknown type!");
|
throw new IllegalArgumentException("Comment on unknown type!");
|
||||||
|
|
||||||
Transaction txn = db.startTransaction(false);
|
|
||||||
try {
|
try {
|
||||||
// Wrap post that we are commenting on
|
// Wrap post that we are commenting on
|
||||||
MessageId parentOriginalId =
|
MessageId parentOriginalId =
|
||||||
@@ -281,6 +288,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
|
|||||||
meta.put(KEY_ORIGINAL_PARENT_MSG_ID, parentOriginalId);
|
meta.put(KEY_ORIGINAL_PARENT_MSG_ID, parentOriginalId);
|
||||||
meta.put(KEY_PARENT_MSG_ID, parentCurrentId);
|
meta.put(KEY_PARENT_MSG_ID, parentCurrentId);
|
||||||
meta.put(KEY_AUTHOR, clientHelper.toList(author));
|
meta.put(KEY_AUTHOR, clientHelper.toList(author));
|
||||||
|
meta.put(KEY_READ, true);
|
||||||
|
|
||||||
// Send comment
|
// Send comment
|
||||||
clientHelper.addLocalMessage(txn, message, meta, true, false);
|
clientHelper.addLocalMessage(txn, message, meta, true, false);
|
||||||
@@ -290,13 +298,10 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
|
|||||||
message.getId(), meta);
|
message.getId(), meta);
|
||||||
BlogPostAddedEvent event = new BlogPostAddedEvent(groupId, h, true);
|
BlogPostAddedEvent event = new BlogPostAddedEvent(groupId, h, true);
|
||||||
txn.attach(event);
|
txn.attach(event);
|
||||||
db.commitTransaction(txn);
|
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
} catch (GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new IllegalArgumentException("Invalid key of author", e);
|
throw new IllegalArgumentException("Invalid key of author", e);
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,18 +434,17 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Blog> getBlogs() throws DbException {
|
public Collection<Blog> getBlogs() throws DbException {
|
||||||
|
return db.transactionWithResult(true, this::getBlogs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Blog> getBlogs(Transaction txn) throws DbException {
|
||||||
try {
|
try {
|
||||||
List<Blog> blogs = new ArrayList<>();
|
List<Blog> blogs = new ArrayList<>();
|
||||||
Collection<Group> groups;
|
Collection<Group> groups =
|
||||||
Transaction txn = db.startTransaction(true);
|
db.getGroups(txn, CLIENT_ID, MAJOR_VERSION);
|
||||||
try {
|
for (Group g : groups) {
|
||||||
groups = db.getGroups(txn, CLIENT_ID, MAJOR_VERSION);
|
blogs.add(blogFactory.parseBlog(g));
|
||||||
for (Group g : groups) {
|
|
||||||
blogs.add(blogFactory.parseBlog(g));
|
|
||||||
}
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
}
|
||||||
return blogs;
|
return blogs;
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
@@ -555,10 +559,18 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setReadFlag(MessageId m, boolean read) throws DbException {
|
public void setReadFlag(MessageId m, boolean read) throws DbException {
|
||||||
|
db.transaction(true, txn -> {
|
||||||
|
setReadFlag(txn, m, read);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadFlag(Transaction txn, MessageId m, boolean read)
|
||||||
|
throws DbException {
|
||||||
try {
|
try {
|
||||||
BdfDictionary meta = new BdfDictionary();
|
BdfDictionary meta = new BdfDictionary();
|
||||||
meta.put(KEY_READ, read);
|
meta.put(KEY_READ, read);
|
||||||
clientHelper.mergeMessageMetadata(m, meta);
|
clientHelper.mergeMessageMetadata(txn, m, meta);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.briarproject.bramble.api.sync.Group;
|
|||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.briarproject.bramble.test.DbExpectations;
|
||||||
import org.briarproject.briar.api.blog.Blog;
|
import org.briarproject.briar.api.blog.Blog;
|
||||||
import org.briarproject.briar.api.blog.BlogCommentHeader;
|
import org.briarproject.briar.api.blog.BlogCommentHeader;
|
||||||
import org.briarproject.briar.api.blog.BlogFactory;
|
import org.briarproject.briar.api.blog.BlogFactory;
|
||||||
@@ -396,12 +397,12 @@ public class BlogManagerImplTest extends BrambleMockTestCase {
|
|||||||
new BdfEntry(KEY_ORIGINAL_MSG_ID, commentId),
|
new BdfEntry(KEY_ORIGINAL_MSG_ID, commentId),
|
||||||
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, messageId),
|
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, messageId),
|
||||||
new BdfEntry(KEY_PARENT_MSG_ID, messageId),
|
new BdfEntry(KEY_PARENT_MSG_ID, messageId),
|
||||||
new BdfEntry(KEY_AUTHOR, authorList1)
|
new BdfEntry(KEY_AUTHOR, authorList1),
|
||||||
|
new BdfEntry(KEY_READ, true)
|
||||||
);
|
);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).startTransaction(false);
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
will(returnValue(txn));
|
|
||||||
// Create the comment
|
// Create the comment
|
||||||
oneOf(blogPostFactory).createBlogComment(blog1.getId(),
|
oneOf(blogPostFactory).createBlogComment(blog1.getId(),
|
||||||
localAuthor1, comment, messageId, messageId);
|
localAuthor1, comment, messageId, messageId);
|
||||||
@@ -422,8 +423,6 @@ public class BlogManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(localAuthor1));
|
will(returnValue(localAuthor1));
|
||||||
oneOf(authorManager).getAuthorInfo(txn, localAuthor1.getId());
|
oneOf(authorManager).getAuthorInfo(txn, localAuthor1.getId());
|
||||||
will(returnValue(ourselvesInfo));
|
will(returnValue(ourselvesInfo));
|
||||||
oneOf(db).commitTransaction(txn);
|
|
||||||
oneOf(db).endTransaction(txn);
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
BlogPostHeader postHeader = new BlogPostHeader(POST, blog1.getId(),
|
BlogPostHeader postHeader = new BlogPostHeader(POST, blog1.getId(),
|
||||||
@@ -492,12 +491,12 @@ public class BlogManagerImplTest extends BrambleMockTestCase {
|
|||||||
new BdfEntry(KEY_ORIGINAL_MSG_ID, commentId),
|
new BdfEntry(KEY_ORIGINAL_MSG_ID, commentId),
|
||||||
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, messageId),
|
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, messageId),
|
||||||
new BdfEntry(KEY_PARENT_MSG_ID, wrappedPostId),
|
new BdfEntry(KEY_PARENT_MSG_ID, wrappedPostId),
|
||||||
new BdfEntry(KEY_AUTHOR, authorList2)
|
new BdfEntry(KEY_AUTHOR, authorList2),
|
||||||
|
new BdfEntry(KEY_READ, true)
|
||||||
);
|
);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).startTransaction(false);
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
will(returnValue(txn));
|
|
||||||
// Wrap the original post for blog 2
|
// Wrap the original post for blog 2
|
||||||
oneOf(clientHelper).getMessageAsList(txn, messageId);
|
oneOf(clientHelper).getMessageAsList(txn, messageId);
|
||||||
will(returnValue(originalPostBody));
|
will(returnValue(originalPostBody));
|
||||||
@@ -533,8 +532,6 @@ public class BlogManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(localAuthor1));
|
will(returnValue(localAuthor1));
|
||||||
oneOf(authorManager).getAuthorInfo(txn, localAuthor1.getId());
|
oneOf(authorManager).getAuthorInfo(txn, localAuthor1.getId());
|
||||||
will(returnValue(verifiedInfo));
|
will(returnValue(verifiedInfo));
|
||||||
oneOf(db).commitTransaction(txn);
|
|
||||||
oneOf(db).endTransaction(txn);
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
BlogPostHeader originalPostHeader = new BlogPostHeader(POST,
|
BlogPostHeader originalPostHeader = new BlogPostHeader(POST,
|
||||||
@@ -603,12 +600,12 @@ public class BlogManagerImplTest extends BrambleMockTestCase {
|
|||||||
new BdfEntry(KEY_ORIGINAL_MSG_ID, commentId),
|
new BdfEntry(KEY_ORIGINAL_MSG_ID, commentId),
|
||||||
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, rssMessageId),
|
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, rssMessageId),
|
||||||
new BdfEntry(KEY_PARENT_MSG_ID, wrappedPostId),
|
new BdfEntry(KEY_PARENT_MSG_ID, wrappedPostId),
|
||||||
new BdfEntry(KEY_AUTHOR, authorList1)
|
new BdfEntry(KEY_AUTHOR, authorList1),
|
||||||
|
new BdfEntry(KEY_READ, true)
|
||||||
);
|
);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).startTransaction(false);
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
will(returnValue(txn));
|
|
||||||
// Wrap the original post for blog 1
|
// Wrap the original post for blog 1
|
||||||
oneOf(clientHelper).getMessageAsList(txn, rssMessageId);
|
oneOf(clientHelper).getMessageAsList(txn, rssMessageId);
|
||||||
will(returnValue(originalPostBody));
|
will(returnValue(originalPostBody));
|
||||||
@@ -642,8 +639,6 @@ public class BlogManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(wrappedPostMeta));
|
will(returnValue(wrappedPostMeta));
|
||||||
oneOf(clientHelper).parseAndValidateAuthor(rssAuthorList);
|
oneOf(clientHelper).parseAndValidateAuthor(rssAuthorList);
|
||||||
will(returnValue(rssLocalAuthor));
|
will(returnValue(rssLocalAuthor));
|
||||||
oneOf(db).commitTransaction(txn);
|
|
||||||
oneOf(db).endTransaction(txn);
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
BlogPostHeader originalPostHeader = new BlogPostHeader(POST,
|
BlogPostHeader originalPostHeader = new BlogPostHeader(POST,
|
||||||
@@ -728,12 +723,12 @@ public class BlogManagerImplTest extends BrambleMockTestCase {
|
|||||||
new BdfEntry(KEY_ORIGINAL_MSG_ID, localCommentId),
|
new BdfEntry(KEY_ORIGINAL_MSG_ID, localCommentId),
|
||||||
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, originalCommentId),
|
new BdfEntry(KEY_ORIGINAL_PARENT_MSG_ID, originalCommentId),
|
||||||
new BdfEntry(KEY_PARENT_MSG_ID, wrappedCommentId),
|
new BdfEntry(KEY_PARENT_MSG_ID, wrappedCommentId),
|
||||||
new BdfEntry(KEY_AUTHOR, authorList2)
|
new BdfEntry(KEY_AUTHOR, authorList2),
|
||||||
|
new BdfEntry(KEY_READ, true)
|
||||||
);
|
);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).startTransaction(false);
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
will(returnValue(txn));
|
|
||||||
// Rewrap the wrapped post for blog 2
|
// Rewrap the wrapped post for blog 2
|
||||||
oneOf(clientHelper).getMessageAsList(txn, wrappedPostId);
|
oneOf(clientHelper).getMessageAsList(txn, wrappedPostId);
|
||||||
will(returnValue(wrappedPostBody));
|
will(returnValue(wrappedPostBody));
|
||||||
@@ -790,8 +785,6 @@ public class BlogManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(rewrappedPostMeta));
|
will(returnValue(rewrappedPostMeta));
|
||||||
oneOf(clientHelper).parseAndValidateAuthor(rssAuthorList);
|
oneOf(clientHelper).parseAndValidateAuthor(rssAuthorList);
|
||||||
will(returnValue(rssLocalAuthor));
|
will(returnValue(rssLocalAuthor));
|
||||||
oneOf(db).commitTransaction(txn);
|
|
||||||
oneOf(db).endTransaction(txn);
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
BlogPostHeader wrappedPostHeader = new BlogPostHeader(WRAPPED_POST,
|
BlogPostHeader wrappedPostHeader = new BlogPostHeader(WRAPPED_POST,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ or to develop your own user interface for it.
|
|||||||
|
|
||||||
The REST API peer comes as a `jar` file
|
The REST API peer comes as a `jar` file
|
||||||
and needs a Java Runtime Environment (JRE) that supports at least Java 8.
|
and needs a Java Runtime Environment (JRE) that supports at least Java 8.
|
||||||
It currently works only on GNU/Linux operating systems and on Windows.
|
It currently works on GNU/Linux operating systems, on Windows and on macOS.
|
||||||
|
|
||||||
To build the `jar` file, you need to specify the combination of architecture and platform:
|
To build the `jar` file, you need to specify the combination of architecture and platform:
|
||||||
|
|
||||||
@@ -17,6 +17,8 @@ To build the `jar` file, you need to specify the combination of architecture and
|
|||||||
$ ./gradlew --configure-on-demand briar-headless:aarch64LinuxJar
|
$ ./gradlew --configure-on-demand briar-headless:aarch64LinuxJar
|
||||||
$ ./gradlew --configure-on-demand briar-headless:armhfLinuxJar
|
$ ./gradlew --configure-on-demand briar-headless:armhfLinuxJar
|
||||||
$ ./gradlew --configure-on-demand briar-headless:windowsJar
|
$ ./gradlew --configure-on-demand briar-headless:windowsJar
|
||||||
|
$ ./gradlew --configure-on-demand briar-headless:x86MacOsJar
|
||||||
|
$ ./gradlew --configure-on-demand briar-headless:aarch64MacOsJar
|
||||||
|
|
||||||
You can start the peer (and its API server) like this:
|
You can start the peer (and its API server) like this:
|
||||||
|
|
||||||
@@ -51,6 +53,11 @@ The answer is an empty JSON array, because you don't have any contacts.
|
|||||||
Note that the HTTP request sets an `Authorization` header with the bearer token.
|
Note that the HTTP request sets an `Authorization` header with the bearer token.
|
||||||
A missing or wrong token will result in a `401` response.
|
A missing or wrong token will result in a `401` response.
|
||||||
|
|
||||||
|
To run on macOS you will need to sign the native tor binaries included in the
|
||||||
|
jar file. To do so, extract the files in `aarch64` or `x86_64` depending on your
|
||||||
|
system architecture, sign them using `codesign` and replace the original files
|
||||||
|
in the jar files with the signed ones.
|
||||||
|
|
||||||
## REST API
|
## REST API
|
||||||
|
|
||||||
### Listing all contacts
|
### Listing all contacts
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ configurations {
|
|||||||
linux {
|
linux {
|
||||||
extendsFrom runtimeClasspath
|
extendsFrom runtimeClasspath
|
||||||
}
|
}
|
||||||
|
macos {
|
||||||
|
extendsFrom runtimeClasspath
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
@@ -38,6 +41,10 @@ dependencies {
|
|||||||
windows "org.briarproject:obfs4proxy-windows:$obfs4proxy_version"
|
windows "org.briarproject:obfs4proxy-windows:$obfs4proxy_version"
|
||||||
windows "org.briarproject:snowflake-windows:$snowflake_version"
|
windows "org.briarproject:snowflake-windows:$snowflake_version"
|
||||||
|
|
||||||
|
macos "org.briarproject:tor-macos:$tor_version"
|
||||||
|
macos "org.briarproject:obfs4proxy-macos:$obfs4proxy_version"
|
||||||
|
macos "org.briarproject:snowflake-macos:$snowflake_version"
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation 'io.javalin:javalin:3.5.0'
|
implementation 'io.javalin:javalin:3.5.0'
|
||||||
implementation 'org.slf4j:slf4j-simple:1.7.30'
|
implementation 'org.slf4j:slf4j-simple:1.7.30'
|
||||||
@@ -89,7 +96,7 @@ void jarFactory(Jar jarTask, os, architecture, configuration) {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
it.duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
|
it.duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
|
||||||
if (os == "linux") {
|
if (os == "linux" || os == "macos") {
|
||||||
String[] architectures = [
|
String[] architectures = [
|
||||||
"aarch64",
|
"aarch64",
|
||||||
"armhf",
|
"armhf",
|
||||||
@@ -100,6 +107,7 @@ void jarFactory(Jar jarTask, os, architecture, configuration) {
|
|||||||
exclude arch + "/obfs4proxy"
|
exclude arch + "/obfs4proxy"
|
||||||
exclude arch + "/tor"
|
exclude arch + "/tor"
|
||||||
exclude arch + "/snowflake"
|
exclude arch + "/snowflake"
|
||||||
|
exclude arch + "/libevent-*.dylib"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,10 +161,22 @@ task windowsJar(type: Jar) {
|
|||||||
jarFactory(it, 'windows', 'x86_64', configurations.windows)
|
jarFactory(it, 'windows', 'x86_64', configurations.windows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task aarch64MacOsJar(type: Jar) {
|
||||||
|
jarFactory(it, 'macos', 'aarch64', configurations.macos)
|
||||||
|
}
|
||||||
|
|
||||||
|
task x86MacOsJar(type: Jar) {
|
||||||
|
jarFactory(it, 'macos', 'x86_64', configurations.macos)
|
||||||
|
}
|
||||||
|
|
||||||
task linuxJars {
|
task linuxJars {
|
||||||
dependsOn(aarch64LinuxJar, armhfLinuxJar, x86LinuxJar)
|
dependsOn(aarch64LinuxJar, armhfLinuxJar, x86LinuxJar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task macosJars {
|
||||||
|
dependsOn(aarch64MacOsJar, x86MacOsJar)
|
||||||
|
}
|
||||||
|
|
||||||
// At the moment for non-Android projects we need to explicitly mark the code generated by kapt
|
// At the moment for non-Android projects we need to explicitly mark the code generated by kapt
|
||||||
// as 'generated source code' for correct highlighting and resolve in IDE.
|
// as 'generated source code' for correct highlighting and resolve in IDE.
|
||||||
idea {
|
idea {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.briar.headless
|
|||||||
import dagger.Component
|
import dagger.Component
|
||||||
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
||||||
import org.briarproject.bramble.BrambleCoreModule
|
import org.briarproject.bramble.BrambleCoreModule
|
||||||
|
import org.briarproject.bramble.BrambleJavaEagerSingletons
|
||||||
import org.briarproject.bramble.BrambleJavaModule
|
import org.briarproject.bramble.BrambleJavaModule
|
||||||
import org.briarproject.briar.BriarCoreEagerSingletons
|
import org.briarproject.briar.BriarCoreEagerSingletons
|
||||||
import org.briarproject.briar.BriarCoreModule
|
import org.briarproject.briar.BriarCoreModule
|
||||||
@@ -19,7 +20,7 @@ import javax.inject.Singleton
|
|||||||
)
|
)
|
||||||
@Singleton
|
@Singleton
|
||||||
internal interface BriarHeadlessApp : BrambleCoreEagerSingletons, BriarCoreEagerSingletons,
|
internal interface BriarHeadlessApp : BrambleCoreEagerSingletons, BriarCoreEagerSingletons,
|
||||||
HeadlessEagerSingletons {
|
BrambleJavaEagerSingletons, HeadlessEagerSingletons {
|
||||||
|
|
||||||
fun getRouter(): Router
|
fun getRouter(): Router
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory
|
|||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
|
||||||
import org.briarproject.bramble.battery.DefaultBatteryManagerModule
|
import org.briarproject.bramble.battery.DefaultBatteryManagerModule
|
||||||
import org.briarproject.bramble.event.DefaultEventExecutorModule
|
import org.briarproject.bramble.event.DefaultEventExecutorModule
|
||||||
|
import org.briarproject.bramble.plugin.tor.MacTorPluginFactory
|
||||||
import org.briarproject.bramble.plugin.tor.UnixTorPluginFactory
|
import org.briarproject.bramble.plugin.tor.UnixTorPluginFactory
|
||||||
import org.briarproject.bramble.plugin.tor.WindowsTorPluginFactory
|
import org.briarproject.bramble.plugin.tor.WindowsTorPluginFactory
|
||||||
import org.briarproject.bramble.system.ClockModule
|
import org.briarproject.bramble.system.ClockModule
|
||||||
@@ -92,10 +93,12 @@ internal class HeadlessModule(private val appDir: File) {
|
|||||||
@Singleton
|
@Singleton
|
||||||
internal fun providePluginConfig(
|
internal fun providePluginConfig(
|
||||||
unixTor: UnixTorPluginFactory,
|
unixTor: UnixTorPluginFactory,
|
||||||
|
macTor: MacTorPluginFactory,
|
||||||
winTor: WindowsTorPluginFactory
|
winTor: WindowsTorPluginFactory
|
||||||
): PluginConfig {
|
): PluginConfig {
|
||||||
val duplex: List<DuplexPluginFactory> = when {
|
val duplex: List<DuplexPluginFactory> = when {
|
||||||
isLinux() || isMac() -> listOf(unixTor)
|
isLinux() -> listOf(unixTor)
|
||||||
|
isMac() -> listOf(macTor)
|
||||||
isWindows() -> listOf(winTor)
|
isWindows() -> listOf(winTor)
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.github.ajalt.clikt.parameters.options.option
|
|||||||
import com.github.ajalt.clikt.parameters.types.int
|
import com.github.ajalt.clikt.parameters.types.int
|
||||||
import org.bouncycastle.util.encoders.Base64.toBase64String
|
import org.bouncycastle.util.encoders.Base64.toBase64String
|
||||||
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
||||||
|
import org.briarproject.bramble.BrambleJavaEagerSingletons
|
||||||
import org.briarproject.bramble.util.OsUtils.isLinux
|
import org.briarproject.bramble.util.OsUtils.isLinux
|
||||||
import org.briarproject.bramble.util.OsUtils.isMac
|
import org.briarproject.bramble.util.OsUtils.isMac
|
||||||
import org.briarproject.briar.BriarCoreEagerSingletons
|
import org.briarproject.briar.BriarCoreEagerSingletons
|
||||||
@@ -28,7 +29,8 @@ import java.util.logging.Level.INFO
|
|||||||
import java.util.logging.Level.WARNING
|
import java.util.logging.Level.WARNING
|
||||||
import java.util.logging.LogManager
|
import java.util.logging.LogManager
|
||||||
|
|
||||||
private const val DEFAULT_PORT = 7000
|
// On macOS, port 7000 is used by ControlCenter (probably AirPlay), so use a different port
|
||||||
|
private val DEFAULT_PORT = if (isMac()) 7001 else 7000
|
||||||
private val DEFAULT_DATA_DIR = getProperty("user.home") + separator + ".briar"
|
private val DEFAULT_DATA_DIR = getProperty("user.home") + separator + ".briar"
|
||||||
|
|
||||||
private class Main : CliktCommand(
|
private class Main : CliktCommand(
|
||||||
@@ -77,6 +79,7 @@ private class Main : CliktCommand(
|
|||||||
// We need to load the eager singletons directly after making the
|
// We need to load the eager singletons directly after making the
|
||||||
// dependency graphs
|
// dependency graphs
|
||||||
BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app)
|
BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app)
|
||||||
|
BrambleJavaEagerSingletons.Helper.injectEagerSingletons(app)
|
||||||
BriarCoreEagerSingletons.Helper.injectEagerSingletons(app)
|
BriarCoreEagerSingletons.Helper.injectEagerSingletons(app)
|
||||||
HeadlessEagerSingletons.Helper.injectEagerSingletons(app)
|
HeadlessEagerSingletons.Helper.injectEagerSingletons(app)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.briar.headless
|
|||||||
import dagger.Component
|
import dagger.Component
|
||||||
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
||||||
import org.briarproject.bramble.BrambleCoreModule
|
import org.briarproject.bramble.BrambleCoreModule
|
||||||
|
import org.briarproject.bramble.BrambleJavaEagerSingletons
|
||||||
import org.briarproject.bramble.BrambleJavaModule
|
import org.briarproject.bramble.BrambleJavaModule
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent
|
import org.briarproject.bramble.api.crypto.CryptoComponent
|
||||||
import org.briarproject.briar.BriarCoreEagerSingletons
|
import org.briarproject.briar.BriarCoreEagerSingletons
|
||||||
@@ -20,7 +21,7 @@ import javax.inject.Singleton
|
|||||||
)
|
)
|
||||||
@Singleton
|
@Singleton
|
||||||
internal interface BriarHeadlessTestApp : BrambleCoreEagerSingletons, BriarCoreEagerSingletons,
|
internal interface BriarHeadlessTestApp : BrambleCoreEagerSingletons, BriarCoreEagerSingletons,
|
||||||
HeadlessEagerSingletons {
|
BrambleJavaEagerSingletons, HeadlessEagerSingletons {
|
||||||
|
|
||||||
fun getRouter(): Router
|
fun getRouter(): Router
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import okhttp3.Request
|
|||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
||||||
|
import org.briarproject.bramble.BrambleJavaEagerSingletons
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent
|
import org.briarproject.bramble.api.crypto.CryptoComponent
|
||||||
import org.briarproject.briar.BriarCoreEagerSingletons
|
import org.briarproject.briar.BriarCoreEagerSingletons
|
||||||
import org.briarproject.briar.api.test.TestDataCreator
|
import org.briarproject.briar.api.test.TestDataCreator
|
||||||
@@ -38,6 +39,7 @@ abstract class IntegrationTest {
|
|||||||
.headlessTestModule(HeadlessTestModule(dataDir))
|
.headlessTestModule(HeadlessTestModule(dataDir))
|
||||||
.build()
|
.build()
|
||||||
BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app)
|
BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app)
|
||||||
|
BrambleJavaEagerSingletons.Helper.injectEagerSingletons(app)
|
||||||
BriarCoreEagerSingletons.Helper.injectEagerSingletons(app)
|
BriarCoreEagerSingletons.Helper.injectEagerSingletons(app)
|
||||||
HeadlessEagerSingletons.Helper.injectEagerSingletons(app)
|
HeadlessEagerSingletons.Helper.injectEagerSingletons(app)
|
||||||
router = app.getRouter()
|
router = app.getRouter()
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ dependencyVerification {
|
|||||||
'javax.servlet:javax.servlet-api:3.1.0:javax.servlet-api-3.1.0.jar:af456b2dd41c4e82cf54f3e743bc678973d9fe35bd4d3071fa05c7e5333b8482',
|
'javax.servlet:javax.servlet-api:3.1.0:javax.servlet-api-3.1.0.jar:af456b2dd41c4e82cf54f3e743bc678973d9fe35bd4d3071fa05c7e5333b8482',
|
||||||
'net.bytebuddy:byte-buddy-agent:1.12.6:byte-buddy-agent-1.12.6.jar:9b29421fe4650b75fc3ed53590f914c54f932e334b3506cc00296dff73024183',
|
'net.bytebuddy:byte-buddy-agent:1.12.6:byte-buddy-agent-1.12.6.jar:9b29421fe4650b75fc3ed53590f914c54f932e334b3506cc00296dff73024183',
|
||||||
'net.bytebuddy:byte-buddy:1.12.6:byte-buddy-1.12.6.jar:211918dc24f0fdef4335ce8af40ef5616e15e818b962a21146397c7701eb75a7',
|
'net.bytebuddy:byte-buddy:1.12.6:byte-buddy-1.12.6.jar:211918dc24f0fdef4335ce8af40ef5616e15e818b962a21146397c7701eb75a7',
|
||||||
'net.java.dev.jna:jna-platform:4.5.2:jna-platform-4.5.2.jar:f1d00c167d8921c6e23c626ef9f1c3ae0be473c95c68ffa012bc7ae55a87e2d6',
|
'net.java.dev.jna:jna-platform:5.13.0:jna-platform-5.13.0.jar:474d7b88f6e97009b6ec1d98c3024dd95c23187c65dabfbc35331bcac3d173dd',
|
||||||
'net.java.dev.jna:jna:4.5.2:jna-4.5.2.jar:0c8eb7acf67261656d79005191debaba3b6bf5dd60a43735a245429381dbecff',
|
'net.java.dev.jna:jna:5.13.0:jna-5.13.0.jar:66d4f819a062a51a1d5627bffc23fac55d1677f0e0a1feba144aabdd670a64bb',
|
||||||
'net.java.dev.jna:jna:5.6.0:jna-5.6.0.jar:5557e235a8aa2f9766d5dc609d67948f2a8832c2d796cea9ef1d6cbe0b3b7eaf',
|
'net.java.dev.jna:jna:5.6.0:jna-5.6.0.jar:5557e235a8aa2f9766d5dc609d67948f2a8832c2d796cea9ef1d6cbe0b3b7eaf',
|
||||||
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
||||||
'org.apiguardian:apiguardian-api:1.1.0:apiguardian-api-1.1.0.jar:a9aae9ff8ae3e17a2a18f79175e82b16267c246fbbd3ca9dfbbb290b08dcfdd4',
|
'org.apiguardian:apiguardian-api:1.1.0:apiguardian-api-1.1.0.jar:a9aae9ff8ae3e17a2a18f79175e82b16267c246fbbd3ca9dfbbb290b08dcfdd4',
|
||||||
@@ -44,12 +44,15 @@ dependencyVerification {
|
|||||||
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
||||||
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
||||||
'org.briarproject:obfs4proxy-linux:0.0.14-tor2:obfs4proxy-linux-0.0.14-tor2.jar:bb2431092b5ad998ad620b0223e725c0f7e43f1b02af2f097a2544edc1fd9738',
|
'org.briarproject:obfs4proxy-linux:0.0.14-tor2:obfs4proxy-linux-0.0.14-tor2.jar:bb2431092b5ad998ad620b0223e725c0f7e43f1b02af2f097a2544edc1fd9738',
|
||||||
|
'org.briarproject:obfs4proxy-macos:0.0.14-tor2:obfs4proxy-macos-0.0.14-tor2.jar:4a688d3a14d2510dd312213488c8f39ee08e609e47a7300aa12e31ceacb16ce2',
|
||||||
'org.briarproject:obfs4proxy-windows:0.0.14-tor2:obfs4proxy-windows-0.0.14-tor2.jar:b5fbd00a8c35ccf095b265370752390e4cd46055331049c4dfcc236dc9c650ac',
|
'org.briarproject:obfs4proxy-windows:0.0.14-tor2:obfs4proxy-windows-0.0.14-tor2.jar:b5fbd00a8c35ccf095b265370752390e4cd46055331049c4dfcc236dc9c650ac',
|
||||||
'org.briarproject:onionwrapper-core:0.0.2:onionwrapper-core-0.0.2.jar:7038e960c9e59803f0e2c19444dbb5214cd99e5a7463c0a01c45318e07a0eb80',
|
'org.briarproject:onionwrapper-core:0.0.4:onionwrapper-core-0.0.4.jar:28a01a62e96aa763989a8afc325abd3bee54f8021269f91aa48b247a6e717870',
|
||||||
'org.briarproject:onionwrapper-java:0.0.2:onionwrapper-java-0.0.2.jar:87a3f4082174dbbd32c4f5f062b46af1d3fedd8cfa1ec84f6ce6ccb6e3674fb6',
|
'org.briarproject:onionwrapper-java:0.0.4:onionwrapper-java-0.0.4.jar:7806ef878074498653b557e26eb70e6007df3450d6a910a2e9a322f7eb4df442',
|
||||||
'org.briarproject:snowflake-linux:2.5.1:snowflake-linux-2.5.1.jar:edc807dcb7758365970d95525e4749349a27f462d0e2df6505ad1ca65fb296d2',
|
'org.briarproject:snowflake-linux:2.5.1:snowflake-linux-2.5.1.jar:edc807dcb7758365970d95525e4749349a27f462d0e2df6505ad1ca65fb296d2',
|
||||||
|
'org.briarproject:snowflake-macos:2.5.1:snowflake-macos-2.5.1.jar:f6d59471d476860950bb639ac318920caa460c4d6d023cbd6547c742949c84f0',
|
||||||
'org.briarproject:snowflake-windows:2.5.1:snowflake-windows-2.5.1.jar:700ec9c68dc033f544daa4ca3547c89e523aed66500cf4b3ac51fe017c51e7be',
|
'org.briarproject:snowflake-windows:2.5.1:snowflake-windows-2.5.1.jar:700ec9c68dc033f544daa4ca3547c89e523aed66500cf4b3ac51fe017c51e7be',
|
||||||
'org.briarproject:tor-linux:0.4.7.13-2:tor-linux-0.4.7.13-2.jar:1e4ca9e0f724e1f17fcce570832704942cc3be26c4c2eccbe5aae29f35afa307',
|
'org.briarproject:tor-linux:0.4.7.13-2:tor-linux-0.4.7.13-2.jar:1e4ca9e0f724e1f17fcce570832704942cc3be26c4c2eccbe5aae29f35afa307',
|
||||||
|
'org.briarproject:tor-macos:0.4.7.13-2:tor-macos-0.4.7.13-2.jar:3d84fbe667584d24275c6a4cb197bafcb0ead890e4d46acac3317debf0cd3351',
|
||||||
'org.briarproject:tor-windows:0.4.7.13-2:tor-windows-0.4.7.13-2.jar:3a0aa01ed3103cac0c22a91a6f227ab99f7d32ea970ea41558eece484ab49e88',
|
'org.briarproject:tor-windows:0.4.7.13-2:tor-windows-0.4.7.13-2.jar:3a0aa01ed3103cac0c22a91a6f227ab99f7d32ea970ea41558eece484ab49e88',
|
||||||
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
||||||
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
||||||
|
|||||||
Submodule briar-mailbox updated: 64147fd1d0...d887c49ab3
@@ -37,7 +37,7 @@ buildscript {
|
|||||||
junit_version = "4.13.2"
|
junit_version = "4.13.2"
|
||||||
jmock_version = '2.12.0'
|
jmock_version = '2.12.0'
|
||||||
mockwebserver_version = '4.10.0'
|
mockwebserver_version = '4.10.0'
|
||||||
onionwrapper_version = '0.0.2'
|
onionwrapper_version = '0.0.4'
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
// upgrading this let's us run into https://github.com/gradle/gradle/issues/20330
|
// upgrading this let's us run into https://github.com/gradle/gradle/issues/20330
|
||||||
|
|||||||
Reference in New Issue
Block a user