mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-11-26 22:31:16 +00:00
Use Gson for connections
This commit is contained in:
parent
a201cd8789
commit
dcdb6e1129
7 changed files with 78 additions and 102 deletions
|
@ -1,10 +1,8 @@
|
||||||
package com.nutomic.syncthingandroid.test;
|
package com.nutomic.syncthingandroid.test;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.model.Connection;
|
import com.nutomic.syncthingandroid.model.Connections;
|
||||||
import com.nutomic.syncthingandroid.model.Device;
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
import com.nutomic.syncthingandroid.model.Folder;
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
import com.nutomic.syncthingandroid.model.Model;
|
import com.nutomic.syncthingandroid.model.Model;
|
||||||
|
@ -12,7 +10,6 @@ import com.nutomic.syncthingandroid.model.SystemInfo;
|
||||||
import com.nutomic.syncthingandroid.service.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -54,7 +51,7 @@ public class MockRestApi extends RestApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getConnections(OnResultListener1<Map<String, Connection>> listener) {
|
public void getConnections(OnResultListener1<Map<String, Connections>> listener) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,9 @@ import android.text.Editable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.*;
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
@ -22,7 +24,7 @@ import com.google.gson.Gson;
|
||||||
import com.google.zxing.integration.android.IntentIntegrator;
|
import com.google.zxing.integration.android.IntentIntegrator;
|
||||||
import com.google.zxing.integration.android.IntentResult;
|
import com.google.zxing.integration.android.IntentResult;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.model.Connection;
|
import com.nutomic.syncthingandroid.model.Connections;
|
||||||
import com.nutomic.syncthingandroid.model.Device;
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.util.Compression;
|
import com.nutomic.syncthingandroid.util.Compression;
|
||||||
|
@ -32,7 +34,6 @@ import com.nutomic.syncthingandroid.util.Util;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static android.text.TextUtils.isEmpty;
|
import static android.text.TextUtils.isEmpty;
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
|
@ -218,13 +219,13 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
|
||||||
* NOTE: This is only called once on startup, should be called more often to properly display
|
* NOTE: This is only called once on startup, should be called more often to properly display
|
||||||
* version/address changes.
|
* version/address changes.
|
||||||
*/
|
*/
|
||||||
public void onReceiveConnections(Map<String, Connection> connections) {
|
public void onReceiveConnections(Connections connections) {
|
||||||
boolean viewsExist = mSyncthingVersionView != null && mCurrentAddressView != null;
|
boolean viewsExist = mSyncthingVersionView != null && mCurrentAddressView != null;
|
||||||
if (viewsExist && connections.containsKey(mDevice.deviceID)) {
|
if (viewsExist && connections.connections.containsKey(mDevice.deviceID)) {
|
||||||
mCurrentAddressView.setVisibility(VISIBLE);
|
mCurrentAddressView.setVisibility(VISIBLE);
|
||||||
mSyncthingVersionView.setVisibility(VISIBLE);
|
mSyncthingVersionView.setVisibility(VISIBLE);
|
||||||
mCurrentAddressView.setText(connections.get(mDevice.deviceID).address);
|
mCurrentAddressView.setText(connections.connections.get(mDevice.deviceID).address);
|
||||||
mSyncthingVersionView.setText(connections.get(mDevice.deviceID).clientVersion);
|
mSyncthingVersionView.setText(connections.connections.get(mDevice.deviceID).clientVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.activities.MainActivity;
|
import com.nutomic.syncthingandroid.activities.MainActivity;
|
||||||
import com.nutomic.syncthingandroid.activities.SettingsActivity;
|
import com.nutomic.syncthingandroid.activities.SettingsActivity;
|
||||||
import com.nutomic.syncthingandroid.activities.WebGuiActivity;
|
import com.nutomic.syncthingandroid.activities.WebGuiActivity;
|
||||||
import com.nutomic.syncthingandroid.model.Connection;
|
import com.nutomic.syncthingandroid.model.Connections;
|
||||||
import com.nutomic.syncthingandroid.model.SystemInfo;
|
import com.nutomic.syncthingandroid.model.SystemInfo;
|
||||||
import com.nutomic.syncthingandroid.model.SystemVersion;
|
import com.nutomic.syncthingandroid.model.SystemVersion;
|
||||||
import com.nutomic.syncthingandroid.service.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
|
@ -187,8 +187,8 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
|
||||||
/**
|
/**
|
||||||
* Populates views with status received via {@link RestApi#getConnections}.
|
* Populates views with status received via {@link RestApi#getConnections}.
|
||||||
*/
|
*/
|
||||||
private void onReceiveConnections(Map<String, Connection> connections) {
|
private void onReceiveConnections(Connections connections) {
|
||||||
Connection c = connections.get(RestApi.TOTAL_STATS);
|
Connections.Connection c = connections.total;
|
||||||
mDownload.setText(Util.readableTransferRate(mActivity, c.inBits));
|
mDownload.setText(Util.readableTransferRate(mActivity, c.inBits));
|
||||||
mUpload.setText(Util.readableTransferRate(mActivity, c.outBits));
|
mUpload.setText(Util.readableTransferRate(mActivity, c.outBits));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
package com.nutomic.syncthingandroid.model;
|
|
||||||
|
|
||||||
public class Connection {
|
|
||||||
public String at;
|
|
||||||
public long inBytesTotal;
|
|
||||||
public long outBytesTotal;
|
|
||||||
public long inBits;
|
|
||||||
public long outBits;
|
|
||||||
public String address;
|
|
||||||
public String clientVersion;
|
|
||||||
public int completion;
|
|
||||||
public boolean connected;
|
|
||||||
}
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Connections {
|
||||||
|
|
||||||
|
public Connection total;
|
||||||
|
public Map<String, Connection> connections;
|
||||||
|
|
||||||
|
public static class Connection {
|
||||||
|
public boolean paused;
|
||||||
|
public String clientVersion;
|
||||||
|
public String at;
|
||||||
|
public boolean connected;
|
||||||
|
public long inBytesTotal;
|
||||||
|
public long outBytesTotal;
|
||||||
|
public String type;
|
||||||
|
public String address;
|
||||||
|
|
||||||
|
// These fields are not sent from Syncthing, but are populated on the client side.
|
||||||
|
public int completion;
|
||||||
|
public long inBits;
|
||||||
|
public long outBits;
|
||||||
|
|
||||||
|
public void setTransferRate(Connection previous, long msElapsed) {
|
||||||
|
long secondsElapsed = msElapsed / 1000;
|
||||||
|
long inBytes = 8 * (inBytesTotal - previous.inBytesTotal) / secondsElapsed;
|
||||||
|
long outBytes = 8 * (outBytesTotal - previous.outBytesTotal) / secondsElapsed;
|
||||||
|
inBits = Math.max(0, inBytes);
|
||||||
|
outBits = Math.max(0, outBytes);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import android.content.Intent;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.reflect.TypeToken;
|
import com.google.common.reflect.TypeToken;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
@ -21,7 +22,7 @@ import com.nutomic.syncthingandroid.http.GetTask;
|
||||||
import com.nutomic.syncthingandroid.http.PostConfigTask;
|
import com.nutomic.syncthingandroid.http.PostConfigTask;
|
||||||
import com.nutomic.syncthingandroid.http.PostScanTask;
|
import com.nutomic.syncthingandroid.http.PostScanTask;
|
||||||
import com.nutomic.syncthingandroid.model.Config;
|
import com.nutomic.syncthingandroid.model.Config;
|
||||||
import com.nutomic.syncthingandroid.model.Connection;
|
import com.nutomic.syncthingandroid.model.Connections;
|
||||||
import com.nutomic.syncthingandroid.model.Device;
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
import com.nutomic.syncthingandroid.model.Event;
|
import com.nutomic.syncthingandroid.model.Event;
|
||||||
import com.nutomic.syncthingandroid.model.Folder;
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
|
@ -31,10 +32,6 @@ import com.nutomic.syncthingandroid.model.SystemInfo;
|
||||||
import com.nutomic.syncthingandroid.model.SystemVersion;
|
import com.nutomic.syncthingandroid.model.SystemVersion;
|
||||||
import com.nutomic.syncthingandroid.util.FolderObserver;
|
import com.nutomic.syncthingandroid.util.FolderObserver;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -51,12 +48,6 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
|
||||||
|
|
||||||
private static final String TAG = "RestApi";
|
private static final String TAG = "RestApi";
|
||||||
|
|
||||||
/**
|
|
||||||
* Key of the map element containing connection info for the local device, in the return
|
|
||||||
* value of {@link #getConnections}
|
|
||||||
*/
|
|
||||||
public static final String TOTAL_STATS = "total";
|
|
||||||
|
|
||||||
public interface OnConfigChangedListener {
|
public interface OnConfigChangedListener {
|
||||||
void onConfigChanged();
|
void onConfigChanged();
|
||||||
}
|
}
|
||||||
|
@ -83,7 +74,7 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
|
||||||
* Stores the result of the last successful request to {@link GetTask#URI_CONNECTIONS},
|
* Stores the result of the last successful request to {@link GetTask#URI_CONNECTIONS},
|
||||||
* or an empty Map.
|
* or an empty Map.
|
||||||
*/
|
*/
|
||||||
private Map<String, Connection> mPreviousConnections = new HashMap<>();
|
private Optional<Connections> mPreviousConnections = Optional.absent();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the timestamp of the last successful request to {@link GetTask#URI_CONNECTIONS}.
|
* Stores the timestamp of the last successful request to {@link GetTask#URI_CONNECTIONS}.
|
||||||
|
@ -342,62 +333,31 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns connection info for the local device and all connected devices.
|
* Returns connection info for the local device and all connected devices.
|
||||||
* <p/>
|
|
||||||
* Use the key {@link #TOTAL_STATS} to get connection info for the local device.
|
|
||||||
*
|
|
||||||
* The result is cached internally. Do not modify it or any of its contents.
|
|
||||||
*/
|
*/
|
||||||
public void getConnections(final OnResultListener1<Map<String, Connection>> listener) {
|
public void getConnections(final OnResultListener1<Connections> listener) {
|
||||||
new GetTask(mUrl, GetTask.URI_CONNECTIONS, mHttpsCertPath, mApiKey, null, result -> {
|
new GetTask(mUrl, GetTask.URI_CONNECTIONS, mHttpsCertPath, mApiKey, null, result -> {
|
||||||
Long now = System.currentTimeMillis();
|
Long now = System.currentTimeMillis();
|
||||||
Long timeElapsed = (now - mPreviousConnectionTime) / 1000;
|
Long msElapsed = now - mPreviousConnectionTime;
|
||||||
if (timeElapsed < 1) {
|
if (msElapsed < SyncthingService.GUI_UPDATE_INTERVAL) {
|
||||||
listener.onResult(mPreviousConnections);
|
listener.onResult(deepCopy(mPreviousConnections.get(), Connections.class));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
mPreviousConnectionTime = now;
|
||||||
JSONObject json = new JSONObject(result);
|
Connections connections = new Gson().fromJson(result, Connections.class);
|
||||||
Map<String, JSONObject> jsonConnections = new HashMap<>();
|
for (Map.Entry<String, Connections.Connection> e : connections.connections.entrySet()) {
|
||||||
jsonConnections.put(TOTAL_STATS, json.getJSONObject(TOTAL_STATS));
|
e.getValue().completion = getDeviceCompletion(e.getKey());
|
||||||
JSONArray extConnections = json.getJSONObject("connections").names();
|
|
||||||
if (extConnections != null) {
|
|
||||||
for (int i = 0; i < extConnections.length(); i++) {
|
|
||||||
String deviceId = extConnections.get(i).toString();
|
|
||||||
jsonConnections.put(deviceId, json.getJSONObject("connections").getJSONObject(deviceId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Map<String, Connection> connections = new HashMap<>();
|
|
||||||
for (Map.Entry<String, JSONObject> jsonConnection : jsonConnections.entrySet()) {
|
|
||||||
String deviceId = jsonConnection.getKey();
|
|
||||||
Connection c = new Connection();
|
|
||||||
JSONObject conn = jsonConnection.getValue();
|
|
||||||
c.address = deviceId;
|
|
||||||
c.at = conn.getString("at");
|
|
||||||
c.inBytesTotal = conn.getLong("inBytesTotal");
|
|
||||||
c.outBytesTotal = conn.getLong("outBytesTotal");
|
|
||||||
c.address = conn.getString("address");
|
|
||||||
c.clientVersion = conn.getString("clientVersion");
|
|
||||||
c.completion = getDeviceCompletion(deviceId);
|
|
||||||
c.connected = conn.getBoolean("connected");
|
|
||||||
|
|
||||||
Connection prev = (mPreviousConnections.containsKey(deviceId))
|
Connections.Connection prev = mPreviousConnections
|
||||||
? mPreviousConnections.get(deviceId)
|
.transform(c -> c.connections.get(e.getKey()))
|
||||||
: new Connection();
|
.or(new Connections.Connection());
|
||||||
mPreviousConnectionTime = now;
|
e.getValue().setTransferRate(prev, msElapsed);
|
||||||
c.inBits = Math.max(0, 8 *
|
|
||||||
(conn.getLong("inBytesTotal") - prev.inBytesTotal) / timeElapsed);
|
|
||||||
c.outBits = Math.max(0, 8 *
|
|
||||||
(conn.getLong("outBytesTotal") - prev.outBytesTotal) / timeElapsed);
|
|
||||||
|
|
||||||
connections.put(deviceId, c);
|
|
||||||
|
|
||||||
}
|
|
||||||
mPreviousConnections = connections;
|
|
||||||
listener.onResult(mPreviousConnections);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
Log.w(TAG, "Failed to parse connections", e);
|
|
||||||
}
|
}
|
||||||
|
Connections.Connection prev =
|
||||||
|
mPreviousConnections.transform(c -> c.total).or(new Connections.Connection());
|
||||||
|
connections.total.setTransferRate(prev, msElapsed);
|
||||||
|
mPreviousConnections = Optional.of(connections);
|
||||||
|
listener.onResult(deepCopy(connections, Connections.class));
|
||||||
}).execute();
|
}).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,22 +10,19 @@ import android.view.ViewGroup;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.model.Connection;
|
import com.nutomic.syncthingandroid.model.Connections;
|
||||||
import com.nutomic.syncthingandroid.model.Device;
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
import com.nutomic.syncthingandroid.service.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
import com.nutomic.syncthingandroid.util.Util;
|
import com.nutomic.syncthingandroid.util.Util;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates item views for device items.
|
* Generates item views for device items.
|
||||||
*/
|
*/
|
||||||
public class DevicesAdapter extends ArrayAdapter<Device> {
|
public class DevicesAdapter extends ArrayAdapter<Device> {
|
||||||
|
|
||||||
private Map<String, Connection> mConnections =
|
private Optional<Connections> mConnections = Optional.absent();
|
||||||
new HashMap<>();
|
|
||||||
|
|
||||||
public DevicesAdapter(Context context) {
|
public DevicesAdapter(Context context) {
|
||||||
super(context, R.layout.item_device_list);
|
super(context, R.layout.item_device_list);
|
||||||
|
@ -46,21 +43,21 @@ public class DevicesAdapter extends ArrayAdapter<Device> {
|
||||||
TextView upload = (TextView) convertView.findViewById(R.id.upload);
|
TextView upload = (TextView) convertView.findViewById(R.id.upload);
|
||||||
|
|
||||||
String deviceId = getItem(position).deviceID;
|
String deviceId = getItem(position).deviceID;
|
||||||
Connection conn = mConnections.get(deviceId);
|
Optional<Connections.Connection> conn = mConnections.transform(a -> a.connections.get(deviceId));
|
||||||
|
|
||||||
name.setText(getItem(position).getDisplayName());
|
name.setText(getItem(position).getDisplayName());
|
||||||
Resources r = getContext().getResources();
|
Resources r = getContext().getResources();
|
||||||
if (conn != null && conn.connected) {
|
if (conn.isPresent() && conn.get().connected) {
|
||||||
if (conn.completion == 100) {
|
if (conn.get().completion == 100) {
|
||||||
status.setText(r.getString(R.string.device_up_to_date));
|
status.setText(r.getString(R.string.device_up_to_date));
|
||||||
status.setTextColor(ContextCompat.getColor(getContext(), R.color.text_green));
|
status.setTextColor(ContextCompat.getColor(getContext(), R.color.text_green));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
status.setText(r.getString(R.string.device_syncing, conn.completion));
|
status.setText(r.getString(R.string.device_syncing, conn.get().completion));
|
||||||
status.setTextColor(ContextCompat.getColor(getContext(), R.color.text_blue));
|
status.setTextColor(ContextCompat.getColor(getContext(), R.color.text_blue));
|
||||||
}
|
}
|
||||||
download.setText(Util.readableTransferRate(getContext(), conn.inBits));
|
download.setText(Util.readableTransferRate(getContext(), conn.get().inBits));
|
||||||
upload.setText(Util.readableTransferRate(getContext(), conn.outBits));
|
upload.setText(Util.readableTransferRate(getContext(), conn.get().outBits));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
download.setText(Util.readableTransferRate(getContext(), 0));
|
download.setText(Util.readableTransferRate(getContext(), 0));
|
||||||
|
@ -81,8 +78,8 @@ public class DevicesAdapter extends ArrayAdapter<Device> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onReceiveConnections(Map<String, Connection> connections) {
|
public void onReceiveConnections(Connections connections) {
|
||||||
mConnections = connections;
|
mConnections = Optional.of(connections);
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue