mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-11-26 22:31:16 +00:00
Added config import/export (fixes #143).
This commit is contained in:
parent
97a324b4b5
commit
527d40e670
5 changed files with 154 additions and 6 deletions
|
@ -7,6 +7,7 @@ import android.test.ServiceTestCase;
|
||||||
import android.test.suitebuilder.annotation.LargeTest;
|
import android.test.suitebuilder.annotation.LargeTest;
|
||||||
import android.test.suitebuilder.annotation.MediumTest;
|
import android.test.suitebuilder.annotation.MediumTest;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.DeviceStateHolder;
|
import com.nutomic.syncthingandroid.syncthing.DeviceStateHolder;
|
||||||
|
@ -14,10 +15,12 @@ import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
|
import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
|
||||||
import com.nutomic.syncthingandroid.test.MockContext;
|
import com.nutomic.syncthingandroid.test.MockContext;
|
||||||
import com.nutomic.syncthingandroid.test.Util;
|
import com.nutomic.syncthingandroid.test.Util;
|
||||||
|
import com.nutomic.syncthingandroid.util.ConfigXml;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -66,7 +69,7 @@ public class SyncthingServiceTest extends ServiceTestCase<SyncthingService> {
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
latch.await(1, TimeUnit.SECONDS);
|
latch.await(5, TimeUnit.SECONDS);
|
||||||
assertNotNull(getService().getApi());
|
assertNotNull(getService().getApi());
|
||||||
assertNotNull(getService().getWebGuiUrl());
|
assertNotNull(getService().getWebGuiUrl());
|
||||||
}
|
}
|
||||||
|
@ -125,4 +128,33 @@ public class SyncthingServiceTest extends ServiceTestCase<SyncthingService> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testImportExportConfig() {
|
||||||
|
setContext(mContext);
|
||||||
|
SyncthingServiceBinder binder = (SyncthingServiceBinder)
|
||||||
|
bindService(new Intent(getContext(), SyncthingService.class));
|
||||||
|
SyncthingService service = binder.getService();
|
||||||
|
File config = new File(mContext.getFilesDir(), ConfigXml.CONFIG_FILE);
|
||||||
|
File privateKey = new File(mContext.getFilesDir(), SyncthingService.PRIVATE_KEY_FILE);
|
||||||
|
File publicKey = new File(mContext.getFilesDir(), SyncthingService.PUBLIC_KEY_FILE);
|
||||||
|
|
||||||
|
try {
|
||||||
|
config.createNewFile();
|
||||||
|
privateKey.createNewFile();
|
||||||
|
publicKey.createNewFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
service.exportConfig();
|
||||||
|
|
||||||
|
config.delete();
|
||||||
|
privateKey.delete();
|
||||||
|
publicKey.delete();
|
||||||
|
|
||||||
|
service.importConfig();
|
||||||
|
assertTrue(config.exists());
|
||||||
|
assertTrue(privateKey.exists());
|
||||||
|
assertTrue(publicKey.exists());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import android.support.v4.preference.PreferenceFragment;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.activities.SyncthingActivity;
|
import com.nutomic.syncthingandroid.activities.SyncthingActivity;
|
||||||
|
@ -20,17 +21,17 @@ import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
||||||
|
|
||||||
public class SettingsFragment extends PreferenceFragment
|
public class SettingsFragment extends PreferenceFragment
|
||||||
implements SyncthingActivity.OnServiceConnectedListener,
|
implements SyncthingActivity.OnServiceConnectedListener,
|
||||||
SyncthingService.OnApiChangeListener, Preference.OnPreferenceChangeListener {
|
SyncthingService.OnApiChangeListener, Preference.OnPreferenceChangeListener,
|
||||||
|
Preference.OnPreferenceClickListener {
|
||||||
|
|
||||||
private static final String TAG = "SettingsFragment";
|
private static final String TAG = "SettingsFragment";
|
||||||
|
|
||||||
private static final String SYNCTHING_OPTIONS_KEY = "syncthing_options";
|
private static final String SYNCTHING_OPTIONS_KEY = "syncthing_options";
|
||||||
|
|
||||||
private static final String SYNCTHING_GUI_KEY = "syncthing_gui";
|
private static final String SYNCTHING_GUI_KEY = "syncthing_gui";
|
||||||
|
|
||||||
private static final String DEVICE_NAME_KEY = "DeviceName";
|
private static final String DEVICE_NAME_KEY = "DeviceName";
|
||||||
|
|
||||||
private static final String USAGE_REPORT_ACCEPTED = "URAccepted";
|
private static final String USAGE_REPORT_ACCEPTED = "URAccepted";
|
||||||
|
private static final String EXPORT_CONFIG = "export_config";
|
||||||
|
private static final String IMPORT_CONFIG = "import_config";
|
||||||
|
|
||||||
private static final String SYNCTHING_VERSION_KEY = "syncthing_version";
|
private static final String SYNCTHING_VERSION_KEY = "syncthing_version";
|
||||||
|
|
||||||
|
@ -134,6 +135,8 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
mAlwaysRunInBackground.setOnPreferenceChangeListener(this);
|
mAlwaysRunInBackground.setOnPreferenceChangeListener(this);
|
||||||
mSyncOnlyCharging.setOnPreferenceChangeListener(this);
|
mSyncOnlyCharging.setOnPreferenceChangeListener(this);
|
||||||
mSyncOnlyWifi.setOnPreferenceChangeListener(this);
|
mSyncOnlyWifi.setOnPreferenceChangeListener(this);
|
||||||
|
screen.findPreference(EXPORT_CONFIG).setOnPreferenceClickListener(this);
|
||||||
|
screen.findPreference(IMPORT_CONFIG).setOnPreferenceClickListener(this);
|
||||||
// Force summary update and wifi/charging preferences enable/disable.
|
// Force summary update and wifi/charging preferences enable/disable.
|
||||||
onPreferenceChange(mAlwaysRunInBackground, mAlwaysRunInBackground.isChecked());
|
onPreferenceChange(mAlwaysRunInBackground, mAlwaysRunInBackground.isChecked());
|
||||||
Preference sttrace = findPreference("sttrace");
|
Preference sttrace = findPreference("sttrace");
|
||||||
|
@ -224,4 +227,27 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
switch (preference.getKey()) {
|
||||||
|
case EXPORT_CONFIG:
|
||||||
|
mSyncthingService.exportConfig();
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.config_export_successful,
|
||||||
|
SyncthingService.EXPORT_PATH), Toast.LENGTH_LONG).show();
|
||||||
|
return true;
|
||||||
|
case IMPORT_CONFIG:
|
||||||
|
if (mSyncthingService.importConfig()) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.config_imported_successful),
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.config_import_failed,
|
||||||
|
SyncthingService.EXPORT_PATH), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
@ -25,8 +26,15 @@ import com.nutomic.syncthingandroid.util.ConfigXml;
|
||||||
import com.nutomic.syncthingandroid.util.FolderObserver;
|
import com.nutomic.syncthingandroid.util.FolderObserver;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
|
import java.io.IOError;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -56,7 +64,12 @@ public class SyncthingService extends Service {
|
||||||
/**
|
/**
|
||||||
* Name of the private key file in the data directory.
|
* Name of the private key file in the data directory.
|
||||||
*/
|
*/
|
||||||
private static final String PRIVATE_KEY_FILE = "key.pem";
|
public static final String PRIVATE_KEY_FILE = "key.pem";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory where config is exported to and imported from.
|
||||||
|
*/
|
||||||
|
public static final File EXPORT_PATH = Environment.getExternalStorageDirectory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the native, integrated syncthing binary, relative to the data folder
|
* Path to the native, integrated syncthing binary, relative to the data folder
|
||||||
|
@ -432,4 +445,60 @@ public class SyncthingService extends Service {
|
||||||
return sp.getBoolean(PREF_ALWAYS_RUN_IN_BACKGROUND, false);
|
return sp.getBoolean(PREF_ALWAYS_RUN_IN_BACKGROUND, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports the local config and keys to {@link #EXPORT_PATH}.
|
||||||
|
*/
|
||||||
|
public void exportConfig() {
|
||||||
|
copyFile(new File(getFilesDir(), ConfigXml.CONFIG_FILE),
|
||||||
|
new File(EXPORT_PATH, ConfigXml.CONFIG_FILE));
|
||||||
|
copyFile(new File(getFilesDir(), PRIVATE_KEY_FILE),
|
||||||
|
new File(EXPORT_PATH, PRIVATE_KEY_FILE));
|
||||||
|
copyFile(new File(getFilesDir(), PUBLIC_KEY_FILE),
|
||||||
|
new File(EXPORT_PATH, PUBLIC_KEY_FILE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports config and keys from {@link #EXPORT_PATH}.
|
||||||
|
*
|
||||||
|
* @return True if the import was successful, false otherwise (eg if files aren't found).
|
||||||
|
*/
|
||||||
|
public boolean importConfig() {
|
||||||
|
File config = new File(EXPORT_PATH, ConfigXml.CONFIG_FILE);
|
||||||
|
File privateKey = new File(EXPORT_PATH, PRIVATE_KEY_FILE);
|
||||||
|
File publicKey = new File(EXPORT_PATH, PUBLIC_KEY_FILE);
|
||||||
|
if (!config.exists() || !privateKey.exists() || !publicKey.exists())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
copyFile(config, new File(getFilesDir(), ConfigXml.CONFIG_FILE));
|
||||||
|
copyFile(privateKey, new File(getFilesDir(), PRIVATE_KEY_FILE));
|
||||||
|
copyFile(publicKey, new File(getFilesDir(), PUBLIC_KEY_FILE));
|
||||||
|
|
||||||
|
startService(new Intent(this, SyncthingService.class)
|
||||||
|
.setAction(SyncthingService.ACTION_RESTART));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies files between different storage devices.
|
||||||
|
*/
|
||||||
|
private void copyFile(File source, File dest) {
|
||||||
|
FileChannel is = null;
|
||||||
|
FileChannel os = null;
|
||||||
|
try {
|
||||||
|
is = new FileInputStream(source).getChannel();
|
||||||
|
os = new FileOutputStream(dest).getChannel();
|
||||||
|
is.transferTo(0, is.size(), os);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to copy file", e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
os.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to close stream", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,6 +250,19 @@ Please report any problems you encounter via Github.</string>
|
||||||
|
|
||||||
<string name="gui_https_enabled">Use HTTPS for GUI</string>
|
<string name="gui_https_enabled">Use HTTPS for GUI</string>
|
||||||
|
|
||||||
|
<string name="export_config">Export Configuration</string>
|
||||||
|
|
||||||
|
<!-- Toast shown after config was successfully exported -->
|
||||||
|
<string name="config_export_successful">Config was exported to %1$s</string>
|
||||||
|
|
||||||
|
<string name="import_config">Import Configuration</string>
|
||||||
|
|
||||||
|
<!-- Toast shown after config was successfully imported -->
|
||||||
|
<string name="config_imported_successful">Config was imported</string>
|
||||||
|
|
||||||
|
<!-- Toast shown after config was successfully imported -->
|
||||||
|
<string name="config_import_failed">Config import failed, make sure files are in %1$s</string>
|
||||||
|
|
||||||
<!-- Title for the preference to set STTRACE parameters -->
|
<!-- Title for the preference to set STTRACE parameters -->
|
||||||
<string name="sttrace_title">Debug Options</string>
|
<string name="sttrace_title">Debug Options</string>
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,14 @@
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="export_config"
|
||||||
|
android:title="@string/export_config" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="import_config"
|
||||||
|
android:title="@string/import_config" />
|
||||||
|
|
||||||
<EditTextPreference
|
<EditTextPreference
|
||||||
android:key="sttrace"
|
android:key="sttrace"
|
||||||
android:title="@string/sttrace_title"
|
android:title="@string/sttrace_title"
|
||||||
|
|
Loading…
Reference in a new issue