Merge branch 'first-swap-overhaul' into 'master'

First swap overhaul

Closes #656, #612, and #586

See merge request fdroid/fdroidclient!671
This commit is contained in:
Hans-Christoph Steiner 2018-04-13 07:45:43 +00:00
commit 714a44ad5d
68 changed files with 533 additions and 359 deletions

View File

@ -40,7 +40,7 @@ dependencies {
compile "info.guardianproject.panic:panic:0.5"
compile 'commons-io:commons-io:2.5'
compile 'commons-net:commons-net:3.5'
compile 'org.openhab.jmdns:jmdns:3.4.2'
compile 'org.jmdns:jmdns:3.5.3'
compile 'ch.acra:acra:4.9.1'
compile 'io.reactivex:rxjava:1.1.0'
compile 'io.reactivex:rxandroid:0.23.0'
@ -137,7 +137,8 @@ if (!hasProperty('sourceDeps')) {
'info.guardianproject.panic:panic:a7ed9439826db2e9901649892cf9afbe76f00991b768d8f4c26332d7c9406cb2',
'io.reactivex:rxandroid:35c1a90f8c1f499db3c1f3d608e1f191ac8afddb10c02dd91ef04c03a0a4bcda',
'io.reactivex:rxjava:2c162afd78eba217cdfee78b60e85d3bfb667db61e12bc95e3cf2ddc5beeadf6',
'org.openhab.jmdns:jmdns:7a4b34b5606bbd2aff7fdfe629edcb0416fccd367fb59a099f210b9aba4f0bce',
'org.jmdns:jmdns:24e7e3a50a579136400e8c9b0750399eb3c7558918bdf52c0ffa5e0fa5aad503',
'org.slf4j:slf4j-api:e56288031f5e60652c06e7bb6e9fa410a61231ab54890f7b708fc6adc4107c5b',
]
}
@ -181,7 +182,6 @@ def preDexEnabled = "true".equals(System.getProperty("pre-dex", "true"))
android {
compileSdkVersion 24
buildToolsVersion '25.0.3'
useLibrary 'org.apache.http.legacy'
buildTypes {
// use proguard on debug too since we have unknowingly broken

View File

@ -7,6 +7,9 @@
-dontwarn com.android.support.test.**
-dontwarn javax.naming.**
-dontwarn org.slf4j.**
-dontnote org.apache.http.**
-dontnote android.net.http.**
-dontnote android.support.**
-dontnote **ILicensingService

View File

@ -4,12 +4,12 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import javax.jmdns.ServiceInfo;
import javax.jmdns.impl.util.ByteWrangler;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.UnknownHostException;
import javax.jmdns.ServiceInfo;
/**
* The ServiceInfo class needs to be serialized in order to be sent as an Android broadcast.
* In order to make it Parcelable (or Serializable for that matter), there are some package-scope
@ -32,7 +32,7 @@ public class FDroidServiceInfo extends ServiceInfoImpl implements Parcelable {
if (data == null || data.length == 0) {
return null;
}
String fingerprint = this.readUTF(data, 0, data.length);
String fingerprint = ByteWrangler.readUTF(data, 0, data.length);
if (TextUtils.isEmpty(fingerprint)) {
return null;
}

View File

@ -47,6 +47,7 @@ import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.data.Schema;
import org.fdroid.fdroid.installer.InstallManagerService;
import org.fdroid.fdroid.net.BluetoothDownloader;
import org.fdroid.fdroid.net.ConnectivityMonitorService;
import org.fdroid.fdroid.views.main.MainActivity;
@ -332,7 +333,7 @@ public class UpdateService extends IntentService {
boolean forcedUpdate = false;
String address = null;
if (intent != null) {
address = intent.getStringExtra(EXTRA_ADDRESS);
address = intent.getStringExtra(EXTRA_ADDRESS); // TODO switch to Intent.setData()
manualUpdate = intent.getBooleanExtra(EXTRA_MANUAL_UPDATE, false);
forcedUpdate = intent.getBooleanExtra(EXTRA_FORCED_UPDATE, false);
}
@ -340,7 +341,9 @@ public class UpdateService extends IntentService {
try {
// See if it's time to actually do anything yet...
int netState = ConnectivityMonitorService.getNetworkState(this);
if (netState == ConnectivityMonitorService.FLAG_NET_UNAVAILABLE) {
if (address != null && address.startsWith(BluetoothDownloader.SCHEME)) {
Utils.debugLog(TAG, "skipping internet check, this is bluetooth");
} else if (netState == ConnectivityMonitorService.FLAG_NET_UNAVAILABLE) {
Utils.debugLog(TAG, "No internet, cannot update");
if (manualUpdate) {
sendNoInternetToast();

View File

@ -1,8 +1,10 @@
package org.fdroid.fdroid.localrepo;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
@ -10,7 +12,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
import android.net.http.AndroidHttpClient;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.IBinder;
import android.support.annotation.IntDef;
@ -20,11 +22,6 @@ import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.Log;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
@ -47,13 +44,14 @@ import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
@ -67,10 +65,13 @@ import java.util.concurrent.ConcurrentHashMap;
public class SwapService extends Service {
private static final String TAG = "SwapService";
private static final String SHARED_PREFERENCES = "swap-state";
private static final String KEY_APPS_TO_SWAP = "appsToSwap";
private static final String KEY_BLUETOOTH_ENABLED = "bluetoothEnabled";
private static final String KEY_WIFI_ENABLED = "wifiEnabled";
private static final String KEY_BLUETOOTH_ENABLED_BEFORE_SWAP = "bluetoothEnabledBeforeSwap";
private static final String KEY_WIFI_ENABLED_BEFORE_SWAP = "wifiEnabledBeforeSwap";
@NonNull
private final Set<String> appsToSwap = new HashSet<>();
@ -80,6 +81,10 @@ public class SwapService extends Service {
*/
private static final ConcurrentHashMap<String, App> INSTALLED_APPS = new ConcurrentHashMap<>();
private static SharedPreferences swapPreferences;
private static BluetoothAdapter bluetoothAdapter;
private static WifiManager wifiManager;
public static void stop(Context context) {
Intent intent = new Intent(context, SwapService.class);
context.stopService(intent);
@ -93,16 +98,6 @@ public class SwapService extends Service {
INSTALLED_APPS.put(packageName, app);
}
/**
* Where relevant, the state of the swap process will be saved to disk using preferences.
* Note that this is not always useful, for example saving the "current wifi network" is
* bound to cause trouble when the user opens the swap process again and is connected to
* a different network.
*/
private SharedPreferences persistence() {
return getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
}
// ==========================================================
// Search for peers to swap
// ==========================================================
@ -208,55 +203,37 @@ public class SwapService extends Service {
UpdateService.updateRepoNow(this, peer.getRepoAddress());
}
@SuppressLint("StaticFieldLeak")
private void askServerToSwapWithUs(final Repo repo) {
askServerToSwapWithUs(repo.address);
}
private void askServerToSwapWithUs(final String address) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... args) {
Uri repoUri = Uri.parse(address);
String swapBackUri = Utils.getLocalRepoUri(FDroidApp.repo).toString();
AndroidHttpClient client = AndroidHttpClient.newInstance("F-Droid", SwapService.this);
HttpPost request = new HttpPost("/request-swap");
HttpHost host = new HttpHost(repoUri.getHost(), repoUri.getPort(), repoUri.getScheme());
HttpURLConnection conn = null;
try {
Utils.debugLog(TAG, "Asking server at " + address + " to swap with us in return (by POSTing to \"/request-swap\" with repo \"" + swapBackUri + "\")...");
populatePostParams(swapBackUri, request);
client.execute(host, request);
URL url = new URL(repo.address.replace("/fdroid/repo", "/request-swap"));
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream outputStream = conn.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
writer.write("repo=" + swapBackUri);
writer.flush();
writer.close();
outputStream.close();
int responseCode = conn.getResponseCode();
Utils.debugLog(TAG, "Asking server at " + repo.address + " to swap with us in return (by " +
"POSTing to \"/request-swap\" with repo \"" + swapBackUri + "\"): " + responseCode);
} catch (IOException e) {
notifyOfErrorOnUiThread();
Log.e(TAG, "Error while asking server to swap with us", e);
} finally {
client.close();
conn.disconnect();
}
return null;
}
private void populatePostParams(String swapBackUri, HttpPost request) throws UnsupportedEncodingException {
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("repo", swapBackUri));
UrlEncodedFormEntity encodedParams = new UrlEncodedFormEntity(params);
request.setEntity(encodedParams);
}
private void notifyOfErrorOnUiThread() {
// TODO: Broadcast error message so that whoever wants to can display a relevant
// message in the UI. This service doesn't understand the concept of UI.
/*runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(
SwapService.this,
R.string.swap_reciprocate_failed,
Toast.LENGTH_LONG
).show();
}
});*/
}
}.execute();
}
@ -333,7 +310,7 @@ public class SwapService extends Service {
// ==========================================
private void persistAppsToSwap() {
persistence().edit().putString(KEY_APPS_TO_SWAP, serializePackages(appsToSwap)).apply();
swapPreferences.edit().putString(KEY_APPS_TO_SWAP, serializePackages(appsToSwap)).apply();
}
/**
@ -389,30 +366,36 @@ public class SwapService extends Service {
persistAppsToSwap();
}
// =============================================================
// Remember which swap technologies a user used in the past
// =============================================================
private final BroadcastReceiver receiveSwapStatusChanged = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Utils.debugLog(TAG, "Remembering that Bluetooth swap " + (bluetoothSwap.isConnected() ? "IS" : "is NOT") +
" connected and WiFi swap " + (wifiSwap.isConnected() ? "IS" : "is NOT") + " connected.");
persistence().edit()
.putBoolean(KEY_BLUETOOTH_ENABLED, bluetoothSwap.isConnected())
.putBoolean(KEY_WIFI_ENABLED, wifiSwap.isConnected())
.apply();
public static boolean getBluetoothVisibleUserPreference() {
return swapPreferences.getBoolean(SwapService.KEY_BLUETOOTH_ENABLED, false);
}
};
/*
private boolean wasBluetoothEnabled() {
return persistence().getBoolean(KEY_BLUETOOTH_ENABLED, false);
public static void putBluetoothVisibleUserPreference(boolean visible) {
swapPreferences.edit().putBoolean(SwapService.KEY_BLUETOOTH_ENABLED, visible).apply();
}
*/
private boolean wasWifiEnabled() {
return persistence().getBoolean(KEY_WIFI_ENABLED, false);
public static boolean getWifiVisibleUserPreference() {
return swapPreferences.getBoolean(SwapService.KEY_WIFI_ENABLED, false);
}
public static void putWifiVisibleUserPreference(boolean visible) {
swapPreferences.edit().putBoolean(SwapService.KEY_WIFI_ENABLED, visible).apply();
}
public static boolean wasBluetoothEnabledBeforeSwap() {
return swapPreferences.getBoolean(SwapService.KEY_BLUETOOTH_ENABLED_BEFORE_SWAP, false);
}
public static void putBluetoothEnabledBeforeSwap(boolean visible) {
swapPreferences.edit().putBoolean(SwapService.KEY_BLUETOOTH_ENABLED_BEFORE_SWAP, visible).apply();
}
public static boolean wasWifiEnabledBeforeSwap() {
return swapPreferences.getBoolean(SwapService.KEY_WIFI_ENABLED_BEFORE_SWAP, false);
}
public static void putWifiEnabledBeforeSwap(boolean visible) {
swapPreferences.edit().putBoolean(SwapService.KEY_WIFI_ENABLED_BEFORE_SWAP, visible).apply();
}
/**
@ -452,9 +435,6 @@ public class SwapService extends Service {
return wifiSwap.isConnected() && wifiSwap.getBonjour().isConnected();
}
public static final String ACTION_PEER_FOUND = "org.fdroid.fdroid.SwapManager.ACTION_PEER_FOUND";
public static final String EXTRA_PEER = "EXTRA_PEER";
// ===============================================================
// Old SwapService stuff being merged into that.
// ===============================================================
@ -503,32 +483,39 @@ public class SwapService extends Service {
CacheSwapAppsService.startCaching(this);
SharedPreferences preferences = getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
swapPreferences = getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
appsToSwap.addAll(deserializePackages(preferences.getString(KEY_APPS_TO_SWAP, "")));
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
SwapService.putBluetoothEnabledBeforeSwap(bluetoothAdapter.isEnabled());
}
wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifiManager != null) {
SwapService.putWifiEnabledBeforeSwap(wifiManager.isWifiEnabled());
}
appsToSwap.addAll(deserializePackages(swapPreferences.getString(KEY_APPS_TO_SWAP, "")));
bluetoothSwap = BluetoothSwap.create(this);
wifiSwap = new WifiSwap(this);
wifiSwap = new WifiSwap(this, wifiManager);
Preferences.get().registerLocalRepoHttpsListeners(httpsEnabledListener);
LocalBroadcastManager.getInstance(this).registerReceiver(onWifiChange, new IntentFilter(WifiStateChangeService.BROADCAST));
LocalBroadcastManager.getInstance(this).registerReceiver(onWifiChange,
new IntentFilter(WifiStateChangeService.BROADCAST));
IntentFilter filter = new IntentFilter(BLUETOOTH_STATE_CHANGE);
filter.addAction(WIFI_STATE_CHANGE);
LocalBroadcastManager.getInstance(this).registerReceiver(receiveSwapStatusChanged, filter);
/*
if (wasBluetoothEnabled()) {
if (getBluetoothVisibleUserPreference()) {
Utils.debugLog(TAG, "Previously the user enabled Bluetooth swap, so enabling again automatically.");
bluetoothSwap.startInBackground();
}
*/
if (wasWifiEnabled()) {
Utils.debugLog(TAG, "Previously the user enabled WiFi swap, so enabling again automatically.");
wifiSwap.startInBackground();
bluetoothSwap.startInBackground(); // TODO replace with Intent to SwapService
} else {
Utils.debugLog(TAG, "WiFi was NOT enabled last time user swapped, so starting with WiFi not visible.");
Utils.debugLog(TAG, "Bluetooth was NOT enabled last time user swapped, starting not visible.");
}
if (getWifiVisibleUserPreference()) {
Utils.debugLog(TAG, "Previously the user enabled WiFi swap, so enabling again automatically.");
wifiSwap.startInBackground(); // TODO replace with Intent to SwapService
} else {
Utils.debugLog(TAG, "WiFi was NOT enabled last time user swapped, starting not visible.");
}
}
@ -549,7 +536,14 @@ public class SwapService extends Service {
Utils.debugLog(TAG, "Destroying service, will disable swapping if required, and unregister listeners.");
Preferences.get().unregisterLocalRepoHttpsListeners(httpsEnabledListener);
LocalBroadcastManager.getInstance(this).unregisterReceiver(onWifiChange);
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiveSwapStatusChanged);
if (!SwapService.wasBluetoothEnabledBeforeSwap()) {
bluetoothAdapter.disable();
}
if (!SwapService.wasWifiEnabledBeforeSwap()) {
wifiManager.setWifiEnabled(false);
}
//TODO getBluetoothSwap().stopInBackground();
getWifiSwap().stopInBackground();

View File

@ -8,7 +8,6 @@ import android.content.IntentFilter;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.net.bluetooth.BluetoothServer;
@ -59,8 +58,8 @@ public final class BluetoothSwap extends SwapType {
@Override
public synchronized void start() {
if (isConnected()) {
Utils.debugLog(TAG, "already running, quitting start()");
return;
}
@ -171,10 +170,12 @@ public final class BluetoothSwap extends SwapType {
}
@Override
public void start() { }
public void start() {
}
@Override
public void stop() { }
public void stop() {
}
@Override
protected String getBroadcastAction() {

View File

@ -2,6 +2,7 @@ package org.fdroid.fdroid.localrepo.type;
import android.annotation.SuppressLint;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@ -31,10 +32,12 @@ public class WifiSwap extends SwapType {
private Handler webServerThreadHandler;
private LocalHTTPD localHttpd;
private final BonjourBroadcast bonjourBroadcast;
private final WifiManager wifiManager;
public WifiSwap(Context context) {
public WifiSwap(Context context, WifiManager wifiManager) {
super(context);
bonjourBroadcast = new BonjourBroadcast(context);
this.wifiManager = wifiManager;
}
protected String getBroadcastAction() {
@ -47,6 +50,8 @@ public class WifiSwap extends SwapType {
@Override
public void start() {
wifiManager.setWifiEnabled(true);
Utils.debugLog(TAG, "Preparing swap webserver.");
sendBroadcast(SwapService.EXTRA_STARTING);

View File

@ -14,15 +14,27 @@ import org.fdroid.fdroid.net.bluetooth.httpish.Response;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Pattern;
/**
* Download from a Bluetooth swap repo. Example URI:
* {@code bluetooth://84-CF-BF-8B-3E-34/fdroid/repo}
*/
public class BluetoothDownloader extends Downloader {
private static final String TAG = "BluetoothDownloader";
public static final String SCHEME = "bluetooth";
private final BluetoothConnection connection;
private FileDetails fileDetails;
private final String sourcePath;
public static boolean isBluetoothUri(Uri uri) {
return SCHEME.equals(uri.getScheme())
&& Pattern.matches("([0-9A-F]{2}-)+[0-9A-F]{2}", uri.getHost());
}
public BluetoothDownloader(Uri uri, File destFile) throws IOException {
super(uri, destFile);
String macAddress = uri.getHost().replace("-", ":");

View File

@ -122,16 +122,23 @@ public class HttpDownloader extends Downloader {
cacheTag = connection.getHeaderField(HEADER_FIELD_ETAG);
}
private boolean isSwapUrl() {
String host = sourceUrl.getHost();
return sourceUrl.getPort() > 1023 // only root can use <= 1023, so never a swap repo
public static boolean isSwapUrl(Uri uri) {
return isSwapUrl(uri.getHost(), uri.getPort());
}
public static boolean isSwapUrl(URL url) {
return isSwapUrl(url.getHost(), url.getPort());
}
public static boolean isSwapUrl(String host, int port) {
return port > 1023 // only root can use <= 1023, so never a swap repo
&& host.matches("[0-9.]+") // host must be an IP address
&& FDroidApp.subnetInfo.isInRange(host); // on the same subnet as we are
}
private HttpURLConnection getConnection() throws SocketTimeoutException, IOException {
HttpURLConnection connection;
if (isSwapUrl()) {
if (isSwapUrl(sourceUrl)) {
// swap never works with a proxy, its unrouted IP on the same subnet
connection = (HttpURLConnection) sourceUrl.openConnection();
} else {

View File

@ -66,7 +66,7 @@ public class BluetoothServer extends Thread {
public void run() {
isRunning = true;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
try {
serverSocket = adapter.listenUsingInsecureRfcommWithServiceRecord("FDroid App Swap", BluetoothConstants.fdroidUuid());
@ -83,6 +83,11 @@ public class BluetoothServer extends Thread {
break;
}
if (!adapter.isEnabled()) {
Utils.debugLog(TAG, "User disabled Bluetooth from outside, stopping.");
break;
}
try {
BluetoothSocket clientSocket = serverSocket.accept();
if (clientSocket != null) {

View File

@ -0,0 +1,149 @@
package org.fdroid.fdroid.views.swap;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.LightingColorFilter;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.QrGenAsyncTask;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.net.WifiStateChangeService;
import org.fdroid.fdroid.views.swap.device.camera.CameraCharacteristicsChecker;
public class SendFDroidView extends ScrollView implements SwapWorkflowActivity.InnerView {
private static final String TAG = "SendFDroidView";
public SendFDroidView(Context context) {
super(context);
}
public SendFDroidView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SendFDroidView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(21)
public SendFDroidView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
private SwapWorkflowActivity getActivity() {
return (SwapWorkflowActivity) getContext();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
setUIFromWifi();
setUpWarningMessageQrScan();
ImageView qrImage = (ImageView) findViewById(R.id.wifi_qr_code);
// Replace all blacks with the background blue.
qrImage.setColorFilter(new LightingColorFilter(0xffffffff, getResources().getColor(R.color.swap_blue)));
Button useBluetooth = (Button) findViewById(R.id.btn_use_bluetooth);
useBluetooth.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().showIntro();
getActivity().sendFDroidBluetooth();
}
});
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
onWifiStateChanged, new IntentFilter(WifiStateChangeService.BROADCAST));
}
private void setUpWarningMessageQrScan() {
final View qrWarningMessage = findViewById(R.id.warning_qr_scanner);
final boolean hasAutofocus = CameraCharacteristicsChecker.getInstance(getContext()).hasAutofocus();
final int visiblity = hasAutofocus ? GONE : VISIBLE;
qrWarningMessage.setVisibility(visiblity);
}
/**
* Remove relevant listeners/receivers/etc so that they do not receive and process events
* when this view is not in use.
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(onWifiStateChanged);
}
@Override
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
return false;
}
@Override
public int getStep() {
return SwapService.STEP_INTRO;
}
@Override
public int getPreviousStep() {
return SwapService.STEP_INTRO;
}
@ColorRes
public int getToolbarColour() {
return R.color.swap_blue;
}
@Override
public String getToolbarTitle() {
return getResources().getString(R.string.swap_send_fdroid);
}
@SuppressLint("HardwareIds")
private void setUIFromWifi() {
if (TextUtils.isEmpty(FDroidApp.repo.address)) {
return;
}
String scheme = Preferences.get().isLocalRepoHttpsEnabled() ? "https://" : "http://";
// the fingerprint is not useful on the button label
String qrUriString = scheme + FDroidApp.ipAddressString + ":" + FDroidApp.port;
TextView ipAddressView = (TextView) findViewById(R.id.device_ip_address);
ipAddressView.setText(qrUriString);
Utils.debugLog(TAG, "Encoded swap URI in QR Code: " + qrUriString);
new QrGenAsyncTask(getActivity(), R.id.wifi_qr_code).execute(qrUriString);
}
private final BroadcastReceiver onWifiStateChanged = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
setUIFromWifi();
}
};
}

View File

@ -324,6 +324,7 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
viewBluetoothId.setVisibility(View.GONE);
Utils.debugLog(TAG, "Received onCheckChanged(false) for Bluetooth swap, Bluetooth swap disabled successfully.");
}
SwapService.putBluetoothVisibleUserPreference(isChecked);
}
};
@ -344,7 +345,8 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
// and the Bonjour service at the same time. Technically swap will work fine without
// Bonjour, and that is more of a convenience. Thus, we should show feedback once wifi
// is ready, even if Bonjour is not yet.
LocalBroadcastManager.getInstance(getContext()).registerReceiver(onWifiSwapStateChanged, new IntentFilter(SwapService.WIFI_STATE_CHANGE));
LocalBroadcastManager.getInstance(getContext()).registerReceiver(onWifiSwapStateChanged,
new IntentFilter(SwapService.WIFI_STATE_CHANGE));
viewWifiNetwork.setOnClickListener(new OnClickListener() {
@Override
@ -426,6 +428,7 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
Utils.debugLog(TAG, "Received onCheckChanged(false) for WiFi swap, disabling WiFi swap in background thread.");
getManager().getWifiSwap().stopInBackground();
}
SwapService.putWifiVisibleUserPreference(isChecked);
uiUpdateWifiNetwork();
}
};

View File

@ -1,5 +1,6 @@
package org.fdroid.fdroid.views.swap;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
@ -12,8 +13,10 @@ import android.content.ServiceConnection;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.support.annotation.ColorRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
@ -29,10 +32,9 @@ import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import cc.mvdan.accesspoint.WifiApControl;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.NfcHelper;
@ -47,6 +49,8 @@ import org.fdroid.fdroid.installer.Installer;
import org.fdroid.fdroid.localrepo.LocalRepoManager;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.peers.Peer;
import org.fdroid.fdroid.net.BluetoothDownloader;
import org.fdroid.fdroid.net.HttpDownloader;
import java.util.Arrays;
import java.util.Date;
@ -57,8 +61,6 @@ import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import cc.mvdan.accesspoint.WifiApControl;
/**
* This activity will do its best to show the most relevant screen about swapping to the user.
* The problem comes when there are two competing goals - 1) Show the user a list of apps from another
@ -111,6 +113,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private static final int REQUEST_BLUETOOTH_ENABLE_FOR_SWAP = 2;
private static final int REQUEST_BLUETOOTH_DISCOVERABLE = 3;
private static final int REQUEST_BLUETOOTH_ENABLE_FOR_SEND = 4;
private static final int REQUEST_WRITE_SETTINGS_PERMISSION = 5;
private Toolbar toolbar;
private InnerView currentView;
@ -118,6 +121,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private PrepareSwapRepo updateSwappableAppsTask;
private NewRepoConfig confirmSwapConfig;
private LocalBroadcastManager localBroadcastManager;
private WifiManager wifiManager;
@NonNull
private final ServiceConnection serviceConnection = new ServiceConnection() {
@ -183,6 +187,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
container = (ViewGroup) findViewById(R.id.fragment_container);
localBroadcastManager = LocalBroadcastManager.getInstance(this);
wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
new SwapDebug().logStatus();
}
@ -209,8 +214,20 @@ public class SwapWorkflowActivity extends AppCompatActivity {
showRelevantView();
}
/**
* Check whether incoming {@link Intent} is a swap repo, and ensure that
* it is a valid swap URL. The hostname can only be either an IP or
* Bluetooth address.
*/
private void checkIncomingIntent() {
Intent intent = getIntent();
Uri uri = intent.getData();
if (uri != null && !HttpDownloader.isSwapUrl(uri) && !BluetoothDownloader.isBluetoothUri(uri)) {
String msg = getString(R.string.swap_toast_invalid_url, uri);
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
return;
}
if (intent.getBooleanExtra(EXTRA_CONFIRM, false) && !intent.getBooleanExtra(EXTRA_SWAP_INTENT_HANDLED, false)) {
// Storing config in this variable will ensure that when showRelevantView() is next
// run, it will show the connect swap view (if the service is available).
@ -239,32 +256,40 @@ public class SwapWorkflowActivity extends AppCompatActivity {
public void onClick(DialogInterface dialog, int which) {
// Do nothing
}
}
).setPositiveButton(R.string.wifi, new DialogInterface.OnClickListener() {
})
.setPositiveButton(R.string.wifi, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK));
SwapService.putWifiEnabledBeforeSwap(wifiManager.isWifiEnabled());
wifiManager.setWifiEnabled(true);
Intent intent = new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
).setNegativeButton(R.string.wifi_ap, new DialogInterface.OnClickListener() {
})
.setNegativeButton(R.string.wifi_ap, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
promptToSetupWifiAP();
if (Build.VERSION.SDK_INT >= 26) {
showTetheringSettings();
} else if (Build.VERSION.SDK_INT >= 23 && !Settings.System.canWrite(getBaseContext())) {
requestWriteSettingsPermission();
} else {
setupWifiAP();
}
}
).create().show();
})
.create().show();
}
private void promptToSetupWifiAP() {
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
private void setupWifiAP() {
WifiApControl ap = WifiApControl.getInstance(this);
wifiManager.setWifiEnabled(false);
if (!ap.enable()) {
Log.e(TAG, "Could not enable WiFi AP.");
// TODO: Feedback to user?
if (ap.enable()) {
Toast.makeText(this, R.string.swap_toast_hotspot_enabled, Toast.LENGTH_SHORT).show();
} else {
Utils.debugLog(TAG, "WiFi AP enabled.");
// TODO: Seems to be broken some times...
Toast.makeText(this, R.string.swap_toast_could_not_enable_hotspot, Toast.LENGTH_LONG).show();
Log.e(TAG, "Could not enable WiFi AP.");
}
}
@ -408,29 +433,52 @@ public class SwapWorkflowActivity extends AppCompatActivity {
inflateInnerView(R.layout.swap_select_apps);
}
/**
* On {@code android-26}, only apps with privileges can access
* {@code WRITE_SETTINGS}. So this just shows the tethering settings
* for the user to do it themselves.
*/
public void showTetheringSettings() {
final Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
final ComponentName cn = new ComponentName("com.android.settings",
"com.android.settings.TetherSettings");
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
@TargetApi(23)
public void requestWriteSettingsPermission() {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intent, REQUEST_WRITE_SETTINGS_PERMISSION);
}
public void sendFDroid() {
// If Bluetooth has not been enabled/turned on, then enabling device discoverability
// will automatically enable Bluetooth.
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
if (adapter.getState() != BluetoothAdapter.STATE_ON) {
if (adapter == null
|| Build.VERSION.SDK_INT >= 23 // TODO make Bluetooth work with content:// URIs
|| (!adapter.isEnabled() && getService().getWifiSwap().isConnected())) {
showSendFDroid();
} else {
sendFDroidBluetooth();
}
}
/**
* Send the F-Droid APK via Bluetooth. If Bluetooth has not been
* enabled/turned on, then enabling device discoverability will
* automatically enable Bluetooth.
*/
public void sendFDroidBluetooth() {
if (BluetoothAdapter.getDefaultAdapter().isEnabled()) {
sendFDroidApk();
} else {
Intent discoverBt = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverBt.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);
startActivityForResult(discoverBt, REQUEST_BLUETOOTH_ENABLE_FOR_SEND);
} else {
sendFDroidApk();
}
} else {
new AlertDialog.Builder(this)
.setTitle(R.string.bluetooth_unavailable)
.setMessage(R.string.swap_cant_send_no_bluetooth)
.setNegativeButton(
R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) { }
}
).create().show();
}
}
@ -483,6 +531,10 @@ public class SwapWorkflowActivity extends AppCompatActivity {
inflateInnerView(R.layout.swap_wifi_qr);
}
public void showSendFDroid() {
inflateInnerView(R.layout.swap_send_fdroid);
}
public void showSwapConnected() {
inflateInnerView(R.layout.swap_success);
}
@ -557,23 +609,28 @@ public class SwapWorkflowActivity extends AppCompatActivity {
}
} else if (requestCode == CONNECT_TO_SWAP && resultCode == Activity.RESULT_OK) {
finish();
} else if (requestCode == REQUEST_WRITE_SETTINGS_PERMISSION) {
if (Build.VERSION.SDK_INT >= 23 && Settings.System.canWrite(this)) {
setupWifiAP();
}
} else if (requestCode == REQUEST_BLUETOOTH_ENABLE_FOR_SWAP) {
if (resultCode == RESULT_OK) {
Utils.debugLog(TAG, "User enabled Bluetooth, will make sure we are discoverable.");
ensureBluetoothDiscoverableThenStart();
} else {
// Didn't enable bluetooth
Utils.debugLog(TAG, "User chose not to enable Bluetooth, so doing nothing (i.e. sticking with wifi).");
Utils.debugLog(TAG, "User chose not to enable Bluetooth, so doing nothing");
SwapService.putBluetoothVisibleUserPreference(false);
}
} else if (requestCode == REQUEST_BLUETOOTH_DISCOVERABLE) {
if (resultCode != RESULT_CANCELED) {
Utils.debugLog(TAG, "User made Bluetooth discoverable, will proceed to start bluetooth server.");
getState().getBluetoothSwap().startInBackground();
getState().getBluetoothSwap().startInBackground(); // TODO replace with Intent to SwapService
} else {
Utils.debugLog(TAG, "User chose not to make Bluetooth discoverable, so doing nothing (i.e. sticking with wifi).");
Utils.debugLog(TAG, "User chose not to make Bluetooth discoverable, so doing nothing");
SwapService.putBluetoothVisibleUserPreference(false);
}
} else if (requestCode == REQUEST_BLUETOOTH_ENABLE_FOR_SEND) {
@ -583,12 +640,13 @@ public class SwapWorkflowActivity extends AppCompatActivity {
/**
* The process for setting up bluetooth is as follows:
* * Assume we have bluetooth available (otherwise the button which allowed us to start
* the bluetooth process should not have been available).
* * Ask user to enable (if not enabled yet).
* * Start bluetooth server socket.
* * Enable bluetooth discoverability, so that people can connect to our server socket.
*
* <ul>
* <li>Assume we have bluetooth available (otherwise the button which allowed us to start
* the bluetooth process should not have been available)</li>
* <li>Ask user to enable (if not enabled yet)</li>
* <li>Start bluetooth server socket</li>
* <li>Enable bluetooth discoverability, so that people can connect to our server socket.</li>
* </ul>
* Note that this is a little different than the usual process for bluetooth _clients_, which
* involves pairing and connecting with other devices.
*/
@ -629,7 +687,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
throw new IllegalStateException("Can't start Bluetooth swap because service is null for some strange reason.");
}
service.getBluetoothSwap().startInBackground();
service.getBluetoothSwap().startInBackground(); // TODO replace with Intent to SwapService
}
class PrepareInitialSwapRepo extends PrepareSwapRepo {

View File

@ -7,6 +7,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.LightingColorFilter;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
@ -19,9 +20,6 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.QrGenAsyncTask;
@ -31,9 +29,8 @@ import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.net.WifiStateChangeService;
import org.fdroid.fdroid.views.swap.device.camera.CameraCharacteristicsChecker;
import java.net.URI;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public class WifiQrView extends ScrollView implements SwapWorkflowActivity.InnerView {
@ -142,32 +139,34 @@ public class WifiQrView extends ScrollView implements SwapWorkflowActivity.Inner
ipAddressView.setText(buttonLabel);
Uri sharingUri = Utils.getSharingUri(FDroidApp.repo);
String qrUriString = scheme + sharingUri.getHost();
StringBuilder qrUrlBuilder = new StringBuilder(scheme);
qrUrlBuilder.append(sharingUri.getHost());
if (sharingUri.getPort() != 80) {
qrUriString += ":" + sharingUri.getPort();
qrUrlBuilder.append(':');
qrUrlBuilder.append(sharingUri.getPort());
}
qrUriString += sharingUri.getPath();
qrUrlBuilder.append(sharingUri.getPath());
boolean first = true;
// Andorid provides an API for getting the query parameters and iterating over them:
// Uri.getQueryParameterNames()
// But it is only available on later Android versions. As such we use URLEncodedUtils instead.
List<NameValuePair> parameters = URLEncodedUtils.parse(URI.create(sharingUri.toString()), "UTF-8");
for (NameValuePair parameter : parameters) {
if (!"ssid".equals(parameter.getName())) {
if (Build.VERSION.SDK_INT > 10) {
Set<String> names = sharingUri.getQueryParameterNames();
for (String name : names) {
if (!"ssid".equals(name)) {
if (first) {
qrUriString += "?";
qrUrlBuilder.append('?');
first = false;
} else {
qrUriString += "&";
qrUrlBuilder.append('&');
}
qrUrlBuilder.append(name.toUpperCase(Locale.ENGLISH));
qrUrlBuilder.append('=');
qrUrlBuilder.append(sharingUri.getQueryParameter(name).toUpperCase(Locale.ENGLISH));
}
qrUriString += parameter.getName().toUpperCase(Locale.ENGLISH) + "=" +
parameter.getValue().toUpperCase(Locale.ENGLISH);
}
}
String qrUriString = qrUrlBuilder.toString();
Utils.debugLog(TAG, "Encoded swap URI in QR Code: " + qrUriString);
new QrGenAsyncTask(getActivity(), R.id.wifi_qr_code).execute(qrUriString);
}

View File

@ -58,7 +58,7 @@
<android.support.v7.widget.SwitchCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:checked="true"
android:enabled="false"
android:id="@+id/switch_bluetooth" />
</LinearLayout>
@ -114,7 +114,7 @@
<android.support.v7.widget.SwitchCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:checked="false"
android:enabled="false"
android:id="@+id/switch_wifi" />
</LinearLayout>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<org.fdroid.fdroid.views.swap.SendFDroidView
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/swap_blue"
android:layout_height="match_parent"
android:layout_width="wrap_content">
<LinearLayout android:orientation="vertical"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="250dp"
android:layout_height="250dp"
android:maxHeight="20dp"
android:id="@+id/wifi_qr_code"
tools:src="@drawable/swap_qr_example"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/swap_scan_or_type_url"
style="@style/SwapTheme.Wizard.MainText"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/device_ip_address"
tools:text="http://255.255.255.255:8888"
style="@style/SwapTheme.Wizard.LocalIpAddress"/>
<Button style="@style/SwapTheme.Wizard.OptionButton"
android:text="@string/use_bluetooth"
android:layout_gravity="center"
android:id="@+id/btn_use_bluetooth"/>
<TextView
android:id="@+id/warning_qr_scanner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/warning_scaning_qr_code"
android:visibility="gone"
style="@style/SwapTheme.Wizard.QRScanWarningText"/>
</LinearLayout>
</org.fdroid.fdroid.views.swap.SendFDroidView>

View File

@ -333,10 +333,6 @@
<string name="swap_intro">Verbind en deel programme met mense naby jou.</string>
<string name="swap_confirm">Bevestig uitruil</string>
<string name="swap_qr_isnt_for_swap">Die QR kode jy geskandeer het lyk nie soos \'n uitruil kode nie.</string>
<string name="bluetooth_unavailable">Bluetooth nie beskikbaar nie</string>
<string name="swap_cant_send_no_bluetooth">"Kan nie F-Droid stuur nie, omdat Bluetooth is nie beskikbaar is op
hierdie toestel nie."
</string>
<string name="loading">Laai tans…</string>
<string name="swap_connection_misc_error">\'n Fout het plaasgevind tydens koppeling met die toestel, dit lyk nie asof ons kan uitruil nie!</string>
<string name="swap_not_enabled">Uitruil nie geaktiveer nie</string>

View File

@ -287,8 +287,6 @@
<string name="swap_connecting">جاري الاتصال</string>
<string name="swap_confirm">تأكيد المبادلة</string>
<string name="swap_qr_isnt_for_swap">رمز الاستجابة السريعة الذي تم التقاطه لا يبدو وكأنه رمز المبادلة.</string>
<string name="bluetooth_unavailable">البلوتوث غير متاح</string>
<string name="swap_cant_send_no_bluetooth">لا يمكن إرسال اف-درويد، بسبب أن البلوتوث غير متاح على هذا الجهاز.</string>
<string name="loading">يتم التحميل…</string>
<string name="swap_connection_misc_error">حدث خطأ أثناء الاتصال بالجهاز، ولا يمكن أن يجري المبادلة معه!</string>
<string name="swap_not_enabled">المبادلة غير فعالة</string>

View File

@ -176,15 +176,11 @@
<string name="uninstall_update_confirm">¿Quies trocar esta aplicación pola versión de fábrica?</string>
<string name="perm_costs_money">Quiciabes esto te cueste perres</string>
<string name="loading">Cargando…</string>
<string name="swap_cant_send_no_bluetooth">Nun pue unviase F-droid porque\'l Bluetooth nun ta disponible nesti
preséu.
</string>
<string name="swap_connecting">Coneutando</string>
<string name="swap_cant_find_peers">¿Nun pues alcontrar a quien tas guetando?</string>
<string name="swap_send_fdroid">Unviar F-droid</string>
<string name="swap_qr_isnt_for_swap">El códigu QR qu\'escaniesti nun paez ser un códigu d\'intercambéu.</string>
<string name="swap_connection_misc_error">Asocedió un fallu entrín se coneutaba col preséu, ¡nun podemos facer l\'intercambiu con elli!</string>
<string name="bluetooth_unavailable">Bluetooth non disponible</string>
<string name="swap_confirm">Confirmar intercambéu</string>
<string name="swap_wifi_device_name">Nome del preséu</string>
<string name="swap_visible_bluetooth">Visible pente Bluetooth</string>

View File

@ -324,10 +324,6 @@
<string name="swap_connecting">Злучэнне</string>
<string name="swap_confirm">Пацвердзіць абмен</string>
<string name="swap_qr_isnt_for_swap">QR-код, які вы адсканавалі, не выглядае як код абмену.</string>
<string name="bluetooth_unavailable">Bluetooth не даступны</string>
<string name="swap_cant_send_no_bluetooth">Немагчыма адправіць F-Droid, бо Bluetooth не даступны на гэтай
прыладзе.
</string>
<string name="loading">Загрузка…</string>
<string name="swap_connection_misc_error">Здарылася памылка падчас злучэння з прыладай. Немагчыма прадоўжыць абмен!</string>
<string name="swap_not_enabled">Абмен не ўключаны</string>

View File

@ -220,10 +220,6 @@
</string>
<string name="swap_not_enabled">Забранена размяна</string>
<string name="swap_cant_send_no_bluetooth">Изпращането на F-Droid не е възможно защото липсва Bluetooth
функционалност.
</string>
<string name="bluetooth_unavailable">Липсва Bluetooth</string>
<string name="swap_nearby">Размяна с устройства наоколо</string>
<string name="local_repo_running">F-Droid e в готовност за размяна</string>
<string name="touch_to_configure_local_repo">Натиснете за детайли или да позволите размяна на приложение.</string>

View File

@ -314,8 +314,6 @@
<string name="swap_connecting">མཐུད་བཞིན་པ།</string>
<string name="swap_confirm">བརྗེ་ལེན་གཏན་འཁེལ།</string>
<string name="swap_qr_isnt_for_swap">ཁྱེད་རང་གིས་འཚག་རྒྱག་པའི་QR ཨང་རྟགས་འདི་བརྗེ་ལེན་ཨང་རྟགས་དང་འདྲ་མཚུངས་མིན་འདུག</string>
<string name="bluetooth_unavailable">བྷུ་ལུ་ཊོཐ་མིན་འདུག</string>
<string name="swap_cant_send_no_bluetooth">ཨེཕ་རོཌ་གཏོང་ཐུབ་ཀྱི་མིན་འདུག གང་ཡིན་ཟེར་ན་ཡོ་བྱད་འདིའི་སྒང་ལ་བྷུ་ལུ་ཊོཐ་མིན་འདུག</string>
<string name="loading">བཅུག་བཞིན་པ།..…</string>
<string name="swap_connection_misc_error">ཡོ་བྱད་ལ་མཐུད་པའི་སྐབས་སུ་སྐྱོན་ཤོར་སོང་བས་དེ་དང་མཉམ་དུ་བརྗེ་ལེན་བྱེད་ཐུབ་ཀྱི་མིན་འདུག!</string>
<string name="swap_not_enabled">བརྗེ་ལེན་སྒོ་ཕྱེས་མིན་འདུག</string>

View File

@ -273,8 +273,6 @@
<string name="swap_connecting">Connectant</string>
<string name="swap_confirm">Confirmeu l\'intercanvi</string>
<string name="swap_qr_isnt_for_swap">El codi QR que heu escanejat no sembla un codi d\'intercanvi.</string>
<string name="bluetooth_unavailable">El Bluetooth no està disponible</string>
<string name="swap_cant_send_no_bluetooth">No s\'ha pogut enviar l\'F-Droid perquè el Bluetooth no està disponible en aquest dispositiu.</string>
<string name="loading">S\'està carregant…</string>
<string name="swap_connection_misc_error">S\'ha produït un error en connectar-se al dispositiu. No us podeu connectar!</string>
<string name="swap_not_enabled">Intercanvi no activat</string>

View File

@ -242,10 +242,6 @@
<string name="swap_connecting">Připojování</string>
<string name="swap_confirm">Potvrdit výměnu</string>
<string name="swap_qr_isnt_for_swap">Naskenovaný QR kód nevypadá jako výměnný kód.</string>
<string name="bluetooth_unavailable">Bluetooth nedostupné</string>
<string name="swap_cant_send_no_bluetooth">F-Droid nelze odeslat, protože na tomto přístroji není Bluetooth
dostupné.
</string>
<string name="loading">Načítání…</string>
<string name="swap_not_enabled">Výměna není povolena</string>
<string name="swap_not_enabled_description">Před výměnou je třeba zviditelnit přístroj.</string>

View File

@ -279,9 +279,6 @@
<string name="swap_connecting">Forbinder</string>
<string name="swap_confirm">Bekræft udveksling</string>
<string name="swap_qr_isnt_for_swap">Den QR-kode du skannede ligner ikke en udvekslingskode.</string>
<string name="bluetooth_unavailable">Bluetooth utilgængelig</string>
<string name="swap_cant_send_no_bluetooth">Kan ikke sende F-Droid fordi Bluetooth er utilgængeligt på denne enhed.
</string>
<string name="loading">Indlæser…</string>
<string name="swap_connection_misc_error">Der opstod en fejl under forbindelsen til enheden, kan udveksle med den!</string>
<string name="swap_not_enabled">Udveksling ikke aktiveret</string>

View File

@ -192,7 +192,6 @@
<string name="system_uninstall_button">Deinstallieren</string>
<string name="bluetooth_unavailable">Bluetooth nicht verfügbar</string>
<string name="newPerms">Neu</string>
<string name="perms_new_perm_prefix">Neu:</string>
<string name="interval_1h">Stündlich</string>
@ -276,9 +275,6 @@
Sie keinen gemeinsamen Netzwerkzugang haben, kann einer von Ihnen einen WLAN-Hotspot einrichten.
</string>
<string name="swap_nearby">Tausch in der Nähe</string>
<string name="swap_cant_send_no_bluetooth">F-Droid kann nicht gesendet werden, da Bluetooth auf diesem Gerät nicht
verfügbar ist.
</string>
<string name="loading">Ladevorgang …</string>
<string name="swap_connection_misc_error">Fehler bei der Verbindungsaufnahme zum Zielgerät. Tausch ist nicht möglich!</string>
<string name="swap_not_enabled">Tauschen ist nicht aktiviert</string>

View File

@ -267,10 +267,6 @@
<string name="swap_connecting">Σύνδεση</string>
<string name="swap_confirm">Επιβεβαίωση ανταλλαγής</string>
<string name="swap_qr_isnt_for_swap">Ο κώδικας QR που σαρώσατε δεν μοιάζει με έναν κωδικό ανταλλαγής.</string>
<string name="bluetooth_unavailable">Το Bluetooth δεν είναι διαθέσιμο</string>
<string name="swap_cant_send_no_bluetooth">Δεν μπορείτε να στείλετε το F-Droid επειδή το Bluetooth δεν είναι
διαθέσιμο σε αυτήν τη συσκευή.
</string>
<string name="loading">Φόρτωση…</string>
<string name="swap_connection_misc_error">Παρουσιάστηκε σφάλμα κατά τη σύνδεση με την συσκευή, φαίνεται ότι δεν μπορούμε να ανταλλάξουμε με αυτή!</string>
<string name="swap_not_enabled">Η ανταλλαγή δεν είναι ενεργοποιημένη</string>

View File

@ -272,10 +272,6 @@
<string name="swap_connecting">Konektado</string>
<string name="swap_confirm">Konfirmi interŝanĝon</string>
<string name="swap_qr_isnt_for_swap">La skanita QR-kodo ne estas interŝanĝa kodo.</string>
<string name="bluetooth_unavailable">Bludento ne disponebla</string>
<string name="swap_cant_send_no_bluetooth">Ne povas sendi F-Droid, ĉar Bludento ne estas disponebla en via
aparato.
</string>
<string name="loading">Prilaborado…</string>
<string name="swap_connection_misc_error">Eraro okazis dum konektado al aparato, ne povas interŝanĝi kun ĝi!</string>
<string name="swap_not_enabled">Interŝanĝo malaktiva</string>

View File

@ -236,8 +236,6 @@
<string name="swap_connecting">Conectando</string>
<string name="swap_confirm">Confirmar intercambio</string>
<string name="swap_qr_isnt_for_swap">El código QR escaneado no parece un código de intercambio.</string>
<string name="bluetooth_unavailable">Bluetooth no disponible</string>
<string name="swap_cant_send_no_bluetooth">No se puede enviar F-Droid porque no está disponible Bluetooth en este dispositivo.</string>
<string name="loading">Cargando…</string>
<string name="swap_connection_misc_error">Ocurrió un error mientras se conectaba al dispositivo. ¡No podemos intercambiar con él!</string>
<string name="swap_not_enabled">Intercambio no activado</string>

View File

@ -302,9 +302,6 @@
<string name="swap_connecting">Ühenduse loomine</string>
<string name="swap_confirm">Kinnita vahetus</string>
<string name="swap_qr_isnt_for_swap">Skannitud QR-kood ei paista olevat vahetamise kood.</string>
<string name="bluetooth_unavailable">Bluetooth ei ole saadaval</string>
<string name="swap_cant_send_no_bluetooth">F-Droidi ei saa saata, sest Bluetooth ei ole selles seadmes saadaval.
</string>
<string name="loading">Laadimine…</string>
<string name="swap_not_enabled">Vahetamine ei ole lubatud</string>
<string name="swap_not_enabled_description">Enne vahetamist pead tegema seadme nähtavaks.</string>

View File

@ -293,10 +293,6 @@
sare berera konektatzerik zuetako batek Wi-Fi gune bat sor dezake.
</string>
<string name="swap_qr_isnt_for_swap">Eskaneatu duzun QR kodea ez diruri truke kode bat.</string>
<string name="bluetooth_unavailable">Bluetooth ez dago eskuragarri</string>
<string name="swap_cant_send_no_bluetooth">Ezin da F-Droid bidali, Bluetooth ez dagoelako erabilgarri gailu
honetan.
</string>
<string name="swap_connection_misc_error">Errore bat gertatu da gailura konektatzean, ezin dugu honekin trukatu!</string>
<string name="swap_not_enabled">Trukea ez dago gaituta</string>
<string name="swap_not_enabled_description">Trukatu aurretik, gailua ikusgai jarri behar duzu.</string>

View File

@ -274,8 +274,6 @@
<string name="swap_nfc_description">اگر دوستتان اف‌دروید دارد و NFC اش روشن است، دستگاه هایتان را با هم تماس بدهید.</string>
<string name="swap_join_same_wifi_desc">برای تبادل با استفاده از وای‌فای، مطمئن شوید که روی شبکهٔ یکسانی هستید. اگر به شبکهٔ یکسان دسترسی ندارید، یکی از شما می‌تواند یک هاتسپات وای‌فای ایجاد کند.</string>
<string name="swap_qr_isnt_for_swap">رمز QR ای که اسکن کردید، شبیه یک رمز تبادل نیست.</string>
<string name="bluetooth_unavailable">بلوتوث موجود نیست</string>
<string name="swap_cant_send_no_bluetooth">نمی‌توان اف‌دروید را فرستاد، زیرا بلوتوث روی این دستگاه موجود نیست.</string>
<string name="loading">در حال بارگزاری…</string>
<string name="swap_connection_misc_error">هنگام اتّصال به دستگاه خطایی رخ داد، نمی‌توان تبادل کرد!</string>
<string name="swap_not_enabled">تبادل فعّال نیست</string>

View File

@ -313,10 +313,6 @@
<string name="swap_connecting">Yhdistetään</string>
<string name="swap_confirm">Vahvista vaihto</string>
<string name="swap_qr_isnt_for_swap">Skannaamasi QR-koodi ei näytä vaihtamiseen tarkoitetulta koodilta.</string>
<string name="bluetooth_unavailable">Bluetooth ei ole saatavilla</string>
<string name="swap_cant_send_no_bluetooth">Ei voida lähettää F-Droidia, koska Bluetooth ei ole saatavilla tällä
laitteella.
</string>
<string name="swap_connection_misc_error">Tapahtui virhe yhdistettäessä laitteeseen, vaihtaminen ei onnistu.
</string>
<string name="swap_not_enabled">Vaihtaminen ei ole käytössä</string>

View File

@ -260,10 +260,6 @@
<string name="swap_connecting">Connexion</string>
<string name="swap_confirm">Confirmez l\'échange</string>
<string name="swap_qr_isnt_for_swap">Le code QR que vous avez scanné ne ressemble pas à un code d\'échange.</string>
<string name="bluetooth_unavailable">Bluetooth indisponible</string>
<string name="swap_cant_send_no_bluetooth">Impossible d\'envoyer F-Droid : le Bluetooth n\'est pas disponible sur
cet appareil.
</string>
<string name="swap_not_enabled_description">Votre appareil doit être visible avant de pouvoir commencer l\'échange.</string>
<string name="interval_1h">Toutes les heures</string>

View File

@ -191,7 +191,6 @@
<string name="swap_send_fdroid">Enviar F-Droid</string>
<string name="swap_connecting">Conectando</string>
<string name="swap_confirm">Confirma o intercambio</string>
<string name="bluetooth_unavailable">O Bluetooth non está dispoñible</string>
<string name="loading">Cargando…</string>
<string name="newPerms">Novo</string>
<string name="allPerms">Todo</string>
@ -290,9 +289,6 @@
<string name="swap_qr_isnt_for_swap">O código QR que escaneaches non parece corresponder a un código de
intercambio.
</string>
<string name="swap_cant_send_no_bluetooth">Non se pode enviar, porque o Bluetooth non está dispoñible neste
dispositivo.
</string>
<string name="swap_connection_misc_error">Ocurriu un erro durante a conexión co dispositivo, non se pode realizar o intercambio!</string>
<string name="swap_not_enabled">Intercambio non dispoñible</string>
<string name="swap_not_enabled_description">Antes do intercambio, o teu dispositivo debe estar visible.</string>

View File

@ -227,7 +227,6 @@
<string name="swap_not_visible_wifi">לא גלוי דרך רשת אלחוטית</string>
<string name="swap_wifi_device_name">שם התקן</string>
<string name="swap_connecting">מתבצע חיבור</string>
<string name="bluetooth_unavailable">Bluetooth לא זמין</string>
<string name="loading">בטעינה…</string>
<string name="interval_never">אף פעם</string>
@ -249,7 +248,6 @@
<string name="swap_send_fdroid">שליחת F-Droid</string>
<string name="swap_confirm">אימות ההחלפה</string>
<string name="swap_qr_isnt_for_swap">קוד ה־QR שסרקת לא נראה כמו קוד החלפה.</string>
<string name="swap_cant_send_no_bluetooth">אין אפשרות לשלוח את F-Droid כיוון שה־Bluetooth אינו זמין בהתקן זה.</string>
<string name="swap_not_enabled">ההחלפה מנוטרלת</string>
<string name="swap_not_enabled_description">בטרם ביצוע החלפה, על מכשירך להיות גלוי.</string>

View File

@ -96,9 +96,6 @@
<string name="loading">लोड हो रहा है…</string>
<string name="swap_connection_misc_error">यन्त्र को जोड़ने मैं एक समस्या आ गयी| यन्त्र से अदला-बदली नहीं हो सकती|
</string>
<string name="bluetooth_unavailable">ब्लूटूथ अनुपलब्ध</string>
<string name="swap_cant_send_no_bluetooth">फ-द्रोइड नहीं भेज सकते, क्योंकि ब्लूटूथ इस यन्त्र पे उपलब्ध नहीं है|
</string>
<string name="swap_connecting">जुड़ रहा है</string>
<string name="swap_confirm">अदला-बदली की पुष्टि करे</string>
<string name="swap_qr_isnt_for_swap">QR कोड जो अपने स्कैन किया है वह अदला-बदली का code नहीं है|</string>

View File

@ -315,9 +315,6 @@
<string name="swap_connecting">Spajanje</string>
<string name="swap_confirm">Potvrdi razmjenu</string>
<string name="swap_qr_isnt_for_swap">Čini se da QR kod koji ste skenirali nije kod za razmjenu.</string>
<string name="bluetooth_unavailable">Bluetooth nedostupan</string>
<string name="swap_cant_send_no_bluetooth">Nije uspjelo slanje F-Droida, Bluetooth nije dostupan na ovom uređaju.
</string>
<string name="loading">Učitavanje…</string>
<string name="swap_connection_misc_error">Došlo je do greške prilikom spajanja na uređaj, čini se da razmjena nije
moguća.

View File

@ -269,10 +269,6 @@
<string name="swap_cant_find_peers">Nem találja, amit keres?</string>
<string name="swap_send_fdroid">Az F-Droid küldése</string>
<string name="swap_connecting">Kapcsolódás</string>
<string name="bluetooth_unavailable">A Bluetooth nem érhető el</string>
<string name="swap_cant_send_no_bluetooth">Az F-Droid küldése sikertelen, mivel a Bluetooth nem érhető el ezen az
eszközön.
</string>
<string name="download_pending">Várakozás a letöltés elkezdésére…</string>
<string name="installing">Telepítés…</string>
<string name="uninstalling">Eltávolítás…</string>

View File

@ -294,10 +294,6 @@
<string name="swap_connecting">Menyambung</string>
<string name="swap_confirm">Konfirmasi swap</string>
<string name="swap_qr_isnt_for_swap">Kode QR yang kamu pindai tidak terlihat seperti kode swap.</string>
<string name="bluetooth_unavailable">Bluetooth tidak tersedia</string>
<string name="swap_cant_send_no_bluetooth">Tidak dapat mengirim F-Droid, karena Bluetooth tidak tersedia diperangkat
ini.
</string>
<string name="loading">Memuat…</string>
<string name="swap_connection_misc_error">Galat terjadi ketika menyambungkan ke perangkat, tidak bisa melakukan pertukaran!</string>
<string name="swap_not_enabled">Swap dinonaktifkan</string>

View File

@ -220,7 +220,6 @@
<string name="swap_no_peers_nearby">Gat ekki fundið neinn í nágrenninu til að býtta við.</string>
<string name="swap_connecting">Tengist</string>
<string name="swap_confirm">Staðfesta býtti</string>
<string name="bluetooth_unavailable">Bluetooth er ekki tiltækt</string>
<string name="loading">Hleð inn…</string>
<string name="swap_not_enabled">Forritabýtti eru óvirk</string>
<string name="install_confirm">þarf aðgang að</string>
@ -369,8 +368,6 @@
</string>
<string name="swap_join_this_hotspot">Hjálpaðu vini þínum að tengjast tengipunktinum þínum</string>
<string name="swap_scan_or_type_url">Einn aðili þarf að skanna QR-kóðann, eða slá slóð hins inn í vafra.</string>
<string name="swap_cant_send_no_bluetooth">Get ekki sent F-Droid, því Bluetooth er ekki til taks á þessu tæki.
</string>
<string name="swap_connection_misc_error">Villa kom upp við að tengjast við tækið, ekki er hægt að nota það við býtti!</string>
<string name="swap_not_enabled_description">Áður en farið er í að býtta þarf að gera tækið þitt sýnilegt.</string>

View File

@ -200,7 +200,6 @@
non saranno rimossi. L\'app dopo l\'aggiornamento avrà accesso a:
</string>
<string name="loading">Caricamento…</string>
<string name="bluetooth_unavailable">Bluetooth non disponibile</string>
<string name="swap_connecting">Connessione in corso</string>
<string name="swap_wifi_device_name">Nome del dispositivo</string>
<string name="swap_cant_find_peers">Non riesci a trovare chi stai cercando?</string>
@ -320,9 +319,6 @@
browser.
</string>
<string name="swap_send_fdroid">Invia F-Droid</string>
<string name="swap_cant_send_no_bluetooth">Impossibile inviare F-Droid, perché il Bluetooth non è disponibile su
questo dispositivo.
</string>
<string name="swap_connection_misc_error">È avvenuto un errore durante la connessione al dispositivo, non sembra possibile effettuare lo scambio!</string>
<string name="swap_not_enabled">Scambio non abilitato</string>
<string name="install_confirm_update_no_perms">Vuoi installare una versione aggiornata

View File

@ -210,8 +210,6 @@
<string name="swap_connecting">接続中</string>
<string name="swap_confirm">交換の確認</string>
<string name="swap_qr_isnt_for_swap">読み取ったQRコードは交換コードではないようです。</string>
<string name="bluetooth_unavailable">Bluetoothが利用できません</string>
<string name="swap_cant_send_no_bluetooth">この端末ではBluetoothが利用できないため、F-Droidを送信できません。</string>
<string name="loading">読み込み中</string>
<string name="downloading">ダウンロード中</string>

View File

@ -156,7 +156,6 @@
<string name="swap_choose_apps">Fren Asnas</string>
<string name="swap_wifi_device_name">Isem n yibenk</string>
<string name="swap_confirm">Sentem ambaddal</string>
<string name="bluetooth_unavailable">Bluetooth yella</string>
<string name="interval_never">Warǧin</string>
<string name="keep_week">1 n umalas</string>
<string name="keep_forever">Yal tikelt</string>

View File

@ -249,8 +249,6 @@
<string name="swap_connecting">연결 중</string>
<string name="swap_confirm">교환 확인</string>
<string name="swap_qr_isnt_for_swap">스캔한 QR 코드는 교환 코드가 아닌 것으로 파악됩니다.</string>
<string name="bluetooth_unavailable">블루투스를 사용할 수 없음</string>
<string name="swap_cant_send_no_bluetooth">F-Droid를 보낼 수 없습니다. 이 장치에서 블루투스를 사용할 수 없기 때문입니다.</string>
<string name="loading">불러오는 중…</string>
<string name="swap_connection_misc_error">장치에 연결하는 동안 오류가 발생했습니다. 교환할 수 없습니다!</string>
<string name="swap_not_enabled">교환이 활성화되어 있지 않음</string>

View File

@ -328,8 +328,6 @@
<string name="swap_connecting">ബന്ധിപ്പിക്കുന്നു</string>
<string name="swap_confirm">കെെമാറ്റം സ്ഥിരീകരിക്കുക</string>
<string name="swap_qr_isnt_for_swap">നിങ്ങൾ സ്കാന്‍ ചെയ്ത QR കോഡ് ഒരു സ്വാപ്പ് കോഡ് പോലെ തോന്നുന്നില്ല.</string>
<string name="bluetooth_unavailable">ബ്ലൂടൂത്ത് ലഭ്യമല്ല</string>
<string name="swap_cant_send_no_bluetooth">ബ്ലൂടൂത്ത് ഈ ഉപകരണത്തിൽ ലഭ്യമല്ലാത്തതിനാൽ എഫ്-ഡ്രോയ്ഡ് അയയ്ക്കാൻ കഴിയില്ല.</string>
<string name="loading">ലോഡുചെയ്യുന്നു…</string>
<string name="swap_connection_misc_error">ഉപകരണത്തിലേക്ക് കണക്റ്റുചെയ്യുമ്പോൾ പിശക് സംഭവിച്ചു, അതുമായി കെെമാറ്റം ചെയ്യാന്‍ പറ്റുന്നില്ല!</string>
<string name="swap_not_enabled">കെെമാറ്റം സജ്ജമല്ല</string>

View File

@ -215,7 +215,6 @@
<string name="swap_cant_find_peers">သင္ရွာေနတာကိုမေတြ႕ဘူးလား?</string>
<string name="swap_send_fdroid">F-Droid ပို႔မည္</string>
<string name="swap_connecting">ခ်ိတ္ဆက္ေနသည္</string>
<string name="bluetooth_unavailable">ဘလူးသုဒ္မရရွိႏိုင္ပါ</string>
<string name="loading">ဖြင့္ေနသည္</string>
<string name="newPerms">အသစ္</string>
<string name="allPerms">အားလံုး</string>

View File

@ -212,10 +212,6 @@
<string name="swap_cant_find_peers">Finner du ikke den du leter etter?</string>
<string name="swap_send_fdroid">Oversend F-Droid</string>
<string name="swap_connecting">Kobler til</string>
<string name="bluetooth_unavailable">Blåtann utilgjengelig</string>
<string name="swap_cant_send_no_bluetooth">Kan ikke sende F-Droid siden Blåtann ikke er tilgjengelig på denne
enheten.
</string>
<string name="loading">Laster inn…</string>
<string name="install_confirm">tilgang til</string>
<string name="newPerms">Ny</string>

View File

@ -223,10 +223,6 @@
<string name="swap_connecting">Verbinden</string>
<string name="swap_confirm">Bevestig uitwisseling</string>
<string name="swap_qr_isnt_for_swap">De QR-code die je gescand hebt lijkt geen uitwisselcode te zijn.</string>
<string name="bluetooth_unavailable">Bluetooth niet beschikbaar</string>
<string name="swap_cant_send_no_bluetooth">Kon F-Droid niet verzenden omdat Bluetooth niet beschikbaar is op dit
apparaat.
</string>
<string name="loading">Laden…</string>
<string name="swap_connection_misc_error">Fout bij verbinden met apparaat, we kunnen er niet mee uit te wisselen!</string>
<string name="swap_not_enabled">Uitwisselen niet ingeschakeld</string>

View File

@ -234,10 +234,6 @@
<string name="swap_connecting">Łączenie</string>
<string name="swap_confirm">Potwierdź wymianę</string>
<string name="swap_qr_isnt_for_swap">Kod QR który został zeskanowany nie wygląda na kod do wymiany aplikacji.</string>
<string name="bluetooth_unavailable">Bluetooth nie jest dostępny</string>
<string name="swap_cant_send_no_bluetooth">Nie udało się wysłać F-Droida ponieważ Bluetooth nie jest dostępny na
Twoim urządzeniu.
</string>
<string name="loading">Ładowanie…</string>
<string name="swap_connection_misc_error">Wystąpił błąd podczas łączenia się z urządzeniem wymiana nie powiodła się!</string>
<string name="swap_not_enabled">Wymiana nie jest włączona</string>

View File

@ -250,10 +250,6 @@
<string name="swap_connecting">Conectando</string>
<string name="swap_confirm">Confirmar a permuta</string>
<string name="swap_qr_isnt_for_swap">O código QR que você escaneou não parece com um código de permuta.</string>
<string name="bluetooth_unavailable">Bluetooth não está disponível</string>
<string name="swap_cant_send_no_bluetooth">Não é possível enviar F-Droid, porque o Bluetooth não está disponível
neste dispositivo.
</string>
<string name="loading">Carregando…</string>
<string name="swap_connection_misc_error">Ocorreu um erro ao conectar o dispositivo, não foi possível trocar com ele!</string>
<string name="swap_not_enabled">Permuta não habilitada</string>

View File

@ -301,10 +301,6 @@
<string name="swap_no_peers_nearby">Não foram encontradas pessoas na sua vizinhança.</string>
<string name="swap_confirm">Confirmação de troca</string>
<string name="swap_qr_isnt_for_swap">O código QR digitalizado não parece ser um código de troca.</string>
<string name="bluetooth_unavailable">Bluetooth não disponível</string>
<string name="swap_cant_send_no_bluetooth">Não pode enviar o F-Droid porque o Bluetooth não está ativo no
dispositivo.
</string>
<string name="swap_connection_misc_error">Ocorreu um erro ao estabelecer a ligação e não será possível a troca!</string>
<string name="swap_not_enabled">Troca não ativa</string>
<string name="swap_not_enabled_description">Antes de trocar, o seu dispositivo tem que estar disponível.</string>

View File

@ -259,7 +259,6 @@
<string name="useTor">Folosește Tor</string>
<string name="repo_details">Depozit</string>
<string name="swap_stopping_wifi">Oprire Wi-Fi…</string>
<string name="bluetooth_unavailable">Bluetooth indisponibil</string>
<string name="repo_provider">Depozit: %s</string>
<string name="update_auto_download">Descarcă automat actualizările</string>
@ -451,7 +450,6 @@
<string name="swap_view_available_networks">Atinge pentru a vedea rețelele deschise disponibile</string>
<string name="swap_scan_or_type_url">O persoană trebuie să scaneze codul sau să introducă URL-ul celuilalt într-un browser.</string>
<string name="swap_qr_isnt_for_swap">Codul QR scanat nu arată ca un cod de schimb.</string>
<string name="swap_cant_send_no_bluetooth">Nu s-a putut trimite F-Droid, deoarece conexiunea Bluetooth nu este valabilă pe acest dispozitiv.</string>
<string name="swap_connection_misc_error">Eroare produsă în timpul conectării la dispozitiv, nu se poate face schimbul!</string>
<string name="swap_not_enabled_description">Înaintea schimbului, dispozitivul tău trebuie făcut vizibil.</string>

View File

@ -308,8 +308,6 @@
<string name="swap_no_peers_nearby">Не удается найти людей рядом, чтобы обменяться с ними.</string>
<string name="swap_confirm">Подтвердить обмен</string>
<string name="swap_qr_isnt_for_swap">QR-код, который вы отсканировали, не похож на код обмена.</string>
<string name="bluetooth_unavailable">Bluetooth не доступен</string>
<string name="swap_cant_send_no_bluetooth">Не удается отправить F-Droid, так как Bluetooth не доступен на данном устройстве.</string>
<string name="swap_connection_misc_error">При подключении к устройству произошла ошибка, невозможно провести с ним обмен!</string>
<string name="swap_not_enabled">Обмен не включен</string>
<string name="swap_not_enabled_description">Для выполнения обмена следует сделать ваше устройство видимым.</string>

View File

@ -252,10 +252,6 @@
<string name="swap_connecting">Connetende</string>
<string name="swap_confirm">Cunfirma cumpartzidura</string>
<string name="swap_qr_isnt_for_swap">Su còdighe QR iscansidu non paret unu còdighe de cumpartzidura.</string>
<string name="bluetooth_unavailable">Bluetooth non disponìbile</string>
<string name="swap_cant_send_no_bluetooth">Impossìbile imbiare F-Droid, ca su Bluetooth no est disponìbile in custu
dispositivu.
</string>
<string name="loading">Carrighende…</string>
<string name="swap_not_enabled">Cumpartzidura non abilitada</string>
<string name="swap_not_enabled_description">In antis de cumpartzire, su dispositivu depet èssere postu visìbile.</string>

View File

@ -232,7 +232,6 @@
<string name="swap_cant_find_peers">Nemôžete nájsť koho hľadáte?</string>
<string name="swap_send_fdroid">Poslať F-Droid</string>
<string name="swap_connecting">Pripájam</string>
<string name="bluetooth_unavailable">Bluetooth nedostupný</string>
<string name="loading">Načítavam…</string>
<string name="install_confirm">vyžaduje prístup k</string>
<string name="allPerms">Všetky</string>
@ -257,9 +256,6 @@
<string name="category_Theming">Témy</string>
<string name="swap_not_visible_bluetooth">Nie je viditeľný cez Bluetooth</string>
<string name="swap_not_visible_wifi">Nie je viditeľný cez Wi-Fi</string>
<string name="swap_cant_send_no_bluetooth">Nemožno poslať F-Droid, pretože Bluetooh nie je dostupný na tomto
zariadení.
</string>
<string name="perm_costs_money">Môže stáť peniaze</string>
<string name="menu_flattr">Flattr</string>

View File

@ -344,10 +344,6 @@
<string name="swap_connecting">Kuhakira</string>
<string name="swap_confirm">Tsinhira kutsinhana</string>
<string name="swap_qr_isnt_for_swap">Murau weQR wawanzvera hausi kuita kunge murau wekutsinhana.</string>
<string name="bluetooth_unavailable">Bluetooth haipo</string>
<string name="swap_cant_send_no_bluetooth">Hatisi kukwanisa kutumira F-Droid, nekuti Bluetooth haipo pamuchina
uyu.
</string>
<string name="loading">Kuzadza…</string>
<string name="swap_connection_misc_error">Pane kanganiso yaitika pakuhakira kumuchina, hatisi kukwanisa kutsinhana
nayo.

View File

@ -206,7 +206,6 @@
<string name="swap_send_fdroid">Пошаљи Ф-дроид</string>
<string name="swap_connecting">Повезујем се</string>
<string name="swap_confirm">Потврди размену</string>
<string name="bluetooth_unavailable">Блутут није доступан</string>
<string name="loading">Учитавам…</string>
<string name="swap_not_enabled">Размена није укључена</string>
<string name="newPerms">Ново</string>
@ -238,8 +237,6 @@
<string name="swap_not_enabled_description">Пре размене, ваш уређај мора бити видљив.</string>
<string name="swap_cant_send_no_bluetooth">Не могу да пошаљем Ф-дроида, блутут није доступан на овом уређају.
</string>
<string name="swap_visible_bluetooth">Видљив преко блутута</string>
<string name="swap_not_visible_bluetooth">Нисам видљив преко блутута</string>
<string name="swap_visible_wifi">Видљив преко бежичног</string>

View File

@ -266,8 +266,6 @@
<string name="swap_connecting">Ansluter</string>
<string name="swap_confirm">Bekräfta utbyte</string>
<string name="swap_qr_isnt_for_swap">QR-koden du läst av ser inte ut som en utbytarkod.</string>
<string name="bluetooth_unavailable">Bluetooth inte tillgänglig</string>
<string name="swap_cant_send_no_bluetooth">Det går inte att skicka F-Droid eftersom Bluetooth är otillgänglig på den här enheten.</string>
<string name="loading">Öppnar…</string>
<string name="swap_connection_misc_error">Fel uppstod under enhetsanslutning, går inte att utföra utbyte med den!</string>
<string name="swap_not_enabled">Utbyta inte aktiverat</string>

View File

@ -176,8 +176,6 @@
<string name="swap_send_fdroid">ส่งต่อโปรแกรม F-Droid</string>
<string name="swap_connecting">กำลังเชื่อมต่อ</string>
<string name="swap_confirm">ยืนยันการส่งต่อ</string>
<string name="bluetooth_unavailable">ไม่สามารถใช้บลูทูธได้</string>
<string name="swap_cant_send_no_bluetooth">ไม่สามารถส่งต่อโปรแกรม F-Droid ได้ เนื่องจากไม่สามารถใช้บลูทูธ</string>
<string name="loading">กำลังโหลด…</string>
<string name="swap_connection_misc_error">การเชื่อมต่อกับอีกเครื่องล้มเหลว, ไม่สามารถส่งต่อโปรแกรมได้</string>
<string name="swap_not_enabled">ไม่เปิดใช้การส่งต่อโปรแกรม</string>

View File

@ -261,8 +261,6 @@
<string name="swap_connecting">Bağlanıyor</string>
<string name="swap_confirm">Takası onaylayın</string>
<string name="swap_qr_isnt_for_swap">Taradığınız QR kodu bir takas kodu gibi görünmüyor.</string>
<string name="bluetooth_unavailable">Bluetooth kullanılabilir değil</string>
<string name="swap_cant_send_no_bluetooth">F-Droid gönderilemiyor, çünkü bu aygıtta Bluetooth kullanılabilir değil.</string>
<string name="loading">Yükleniyor…</string>
<string name="swap_connection_misc_error">Aygıta bağlanılırken hata oluştu, onunla takas yapılamaz!</string>
<string name="swap_not_enabled">Takas etkinleştirilmemiş</string>

View File

@ -161,10 +161,6 @@
<string name="swap_wifi_device_name">Назва пристрою</string>
<string name="swap_send_fdroid">Відправити F-Droid</string>
<string name="swap_connecting">Підключення</string>
<string name="bluetooth_unavailable">Bluetooth не доступний</string>
<string name="swap_cant_send_no_bluetooth">Неможливо надіслати F-Droid, тому що Bluetooth не доступний на цьому
пристрої.
</string>
<string name="loading">Завантаження…</string>
<string name="newPerms">Нові</string>
<string name="allPerms">Всі</string>

View File

@ -242,8 +242,6 @@
<string name="swap_connecting">Đang kết nối</string>
<string name="swap_confirm">Xác nhận trao đổi</string>
<string name="swap_qr_isnt_for_swap">Mã QR đã quét không phải là mã trao đổi.</string>
<string name="bluetooth_unavailable">Không có Bluetooth</string>
<string name="swap_cant_send_no_bluetooth">Không thể gửi F-Droid vì thiết bị này không có Bluetooth.</string>
<string name="loading">Đang tải…</string>
<string name="swap_not_enabled">Trao đổi đang tắt</string>
<string name="swap_connection_misc_error">Đã xảy ra lỗi khi kết nối, không thể trao đổi ứng dụng!</string>

View File

@ -246,8 +246,6 @@
<string name="swap_connecting">连接中</string>
<string name="swap_confirm">确认交换</string>
<string name="swap_qr_isnt_for_swap">你扫描的二维码似乎不是一个交换代码。</string>
<string name="bluetooth_unavailable">蓝牙不可用</string>
<string name="swap_cant_send_no_bluetooth">不能发送 F-Droid因为该设备蓝牙不可用。</string>
<string name="loading">加载中…</string>
<string name="swap_connection_misc_error">连接设备时出错,无法交换应用!</string>
<string name="swap_not_enabled">未启用交换功能</string>

View File

@ -209,8 +209,6 @@
<string name="swap_not_enabled">沒有啟用交換功能</string>
<string name="swap_connection_misc_error">與裝置連接時發生了問題,未能進行交換!</string>
<string name="loading">正在載入…</string>
<string name="swap_cant_send_no_bluetooth">因為此裝置沒有藍牙功能,未能傳送 F-Droid。</string>
<string name="bluetooth_unavailable">藍牙不可用</string>
<string name="swap_qr_isnt_for_swap">您所掃描的 QR 碼不是一個交換碼。</string>
<string name="swap_confirm">確定交換</string>
<string name="swap_no_peers_nearby">找不到附近的人進行交換。</string>

View File

@ -220,8 +220,6 @@
<string name="swap_send_fdroid">傳送 F-Droid</string>
<string name="swap_no_peers_nearby">找不到附近的人來進行交換。</string>
<string name="swap_confirm">確認交換</string>
<string name="bluetooth_unavailable">藍牙不可用</string>
<string name="swap_cant_send_no_bluetooth">無法傳送 F-Droid因為此裝置沒有藍牙功能。</string>
<string name="swap_not_enabled">沒有啟用交換功能</string>
<string name="uninstall_confirm">您想要解除安裝此應用程式嗎?</string>
<string name="download_error">下載失敗!</string>

View File

@ -453,13 +453,14 @@ This often occurs with apps installed via Google Play or other sources, if they
<string name="swap_connecting">Connecting</string>
<string name="swap_confirm">Confirm swap</string>
<string name="swap_qr_isnt_for_swap">The QR code you scanned doesn\'t look like a swap code.</string>
<string name="bluetooth_unavailable">Bluetooth unavailable</string>
<string name="swap_cant_send_no_bluetooth">Cannot send F-Droid, because Bluetooth is unavailable on this device.
</string>
<string name="use_bluetooth">Use Bluetooth</string>
<string name="loading">Loading…</string>
<string name="swap_connection_misc_error">Error occurred while connecting to device, can\'t swap with it!</string>
<string name="swap_not_enabled">Swapping not enabled</string>
<string name="swap_not_enabled_description">Before swapping, your device must be made visible.</string>
<string name="swap_toast_invalid_url">Invalid URL for swapping: %1$s</string>
<string name="swap_toast_hotspot_enabled">Wi-Fi Hotspot enabled</string>
<string name="swap_toast_could_not_enable_hotspot">Could not enable Wi-Fi Hotspot!</string>
<string name="install_confirm">needs access to</string>
<string name="install_confirm_update">Do you want to install an update

View File

@ -0,0 +1,36 @@
package org.fdroid.fdroid.net;
import android.net.Uri;
import org.apache.commons.net.util.SubnetUtils;
import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.FDroidApp;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.net.MalformedURLException;
import java.net.URL;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
@Config(constants = BuildConfig.class, sdk = 24)
@RunWith(RobolectricTestRunner.class)
@SuppressWarnings("LineLength")
public class HttpDownloaderTest {
@Test
public void testIsSwapUri() throws MalformedURLException {
FDroidApp.subnetInfo = new SubnetUtils("192.168.0.112/24").getInfo();
String urlString = "http://192.168.0.112:8888/fdroid/repo?fingerprint=113F56CBFA967BA825DD13685A06E35730E0061C6BB046DF88A";
assertTrue(HttpDownloader.isSwapUrl("192.168.0.112", 8888)); // NOPMD
assertTrue(HttpDownloader.isSwapUrl(Uri.parse(urlString)));
assertTrue(HttpDownloader.isSwapUrl(new URL(urlString)));
assertFalse(HttpDownloader.isSwapUrl("192.168.1.112", 8888)); // NOPMD
assertFalse(HttpDownloader.isSwapUrl("192.168.0.112", 80)); // NOPMD
assertFalse(HttpDownloader.isSwapUrl(Uri.parse("https://malware.com:8888")));
assertFalse(HttpDownloader.isSwapUrl(new URL("https://www.google.com")));
}
}