From 5d5cf0b903da3428d65ff81f128af92ac50b3f75 Mon Sep 17 00:00:00 2001 From: Lode Hoste Date: Sun, 22 Mar 2015 22:30:49 +0100 Subject: [PATCH] Streamline SyncthingRunnable Conflicts: src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/RestApiTest.java src/main/java/com/nutomic/syncthingandroid/fragments/SettingsFragment.java src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingRunnable.java src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java src/main/res/values/strings.xml --- .../PollWebGuiAvailableTaskTest.java | 3 +- .../test/syncthing/RestApiTest.java | 3 +- .../test/syncthing/SyncthingRunnableTest.java | 4 +- .../fragments/SettingsFragment.java | 9 +++- .../syncthingandroid/syncthing/RestApi.java | 27 ++++++++++ .../syncthing/SyncthingRunnable.java | 52 ++++++++++++++++--- .../syncthing/SyncthingService.java | 19 +++++-- .../syncthingandroid/util/ConfigXml.java | 4 +- src/main/res/values/strings.xml | 11 ++++ src/main/res/xml/app_settings.xml | 5 ++ 10 files changed, 114 insertions(+), 23 deletions(-) diff --git a/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/PollWebGuiAvailableTaskTest.java b/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/PollWebGuiAvailableTaskTest.java index 9d42a95b..c135cf90 100644 --- a/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/PollWebGuiAvailableTaskTest.java +++ b/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/PollWebGuiAvailableTaskTest.java @@ -30,8 +30,7 @@ public class PollWebGuiAvailableTaskTest extends AndroidTestCase { } public void testPolling() throws InterruptedException { - new SyncthingRunnable(new MockContext(null), - getContext().getApplicationInfo().dataDir + "/" + SyncthingService.BINARY_NAME); + mSyncthing = new SyncthingRunnable(new MockContext(null), SyncthingRunnable.Command.main); String httpsCertPath = getContext().getFilesDir() + "/" + SyncthingService.HTTPS_CERT_FILE; diff --git a/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/RestApiTest.java b/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/RestApiTest.java index 193a21bb..fb29ab56 100644 --- a/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/RestApiTest.java +++ b/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/RestApiTest.java @@ -23,8 +23,7 @@ public class RestApiTest extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); - new SyncthingRunnable(new MockContext(null), - getContext().getApplicationInfo().dataDir + "/" + SyncthingService.BINARY_NAME); + mSyncthing = new SyncthingRunnable(new MockContext(null), SyncthingRunnable.Command.main); ConfigXml config = new ConfigXml(new MockContext(getContext())); config.changeDefaultFolder(); diff --git a/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/SyncthingRunnableTest.java b/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/SyncthingRunnableTest.java index 1f41cb68..b875b4f3 100644 --- a/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/SyncthingRunnableTest.java +++ b/src/androidTest/java/com/nutomic/syncthingandroid/test/syncthing/SyncthingRunnableTest.java @@ -17,9 +17,9 @@ public class SyncthingRunnableTest extends AndroidTestCase { @SmallTest public void testRunning() throws InterruptedException { MockContext context = new MockContext(getContext()); - File testFile = new File(context.getFilesDir(), "was_running"); + File testFile = new File(context.getFilesDir(), SyncthingRunnable.UNIT_TEST_PATH); assertFalse(testFile.exists()); - // Inject a differenct command instead of the syncthing binary for testing. + // Inject a different command instead of the Syncthing binary for testing. new SyncthingRunnable(context, "touch " + testFile.getAbsolutePath() + "; exit\n").run(); assertTrue(testFile.exists()); testFile.delete(); diff --git a/src/main/java/com/nutomic/syncthingandroid/fragments/SettingsFragment.java b/src/main/java/com/nutomic/syncthingandroid/fragments/SettingsFragment.java index a55a5ac1..7ca165f8 100644 --- a/src/main/java/com/nutomic/syncthingandroid/fragments/SettingsFragment.java +++ b/src/main/java/com/nutomic/syncthingandroid/fragments/SettingsFragment.java @@ -37,6 +37,7 @@ public class SettingsFragment extends PreferenceFragment private static final String EXPORT_CONFIG = "export_config"; private static final String IMPORT_CONFIG = "import_config"; private static final String STTRACE = "sttrace"; + private static final String SYNCTHING_RESET = "streset"; private static final String SYNCTHING_VERSION_KEY = "syncthing_version"; @@ -139,12 +140,13 @@ public class SettingsFragment extends PreferenceFragment mSyncOnlyWifi.setOnPreferenceChangeListener(this); screen.findPreference(EXPORT_CONFIG).setOnPreferenceClickListener(this); screen.findPreference(IMPORT_CONFIG).setOnPreferenceClickListener(this); + screen.findPreference(SYNCTHING_RESET).setOnPreferenceClickListener(this); user.setOnPreferenceChangeListener(this); password.setOnPreferenceChangeListener(this); - // Force summary update and wifi/charging preferences enable/disable. - onPreferenceChange(mAlwaysRunInBackground, mAlwaysRunInBackground.isChecked()); sttrace.setOnPreferenceChangeListener(this); + // Force summary update and wifi/charging preferences enable/disable. + onPreferenceChange(mAlwaysRunInBackground, mAlwaysRunInBackground.isChecked()); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity()); user.setSummary(sp.getString("gui_user", "")); sttrace.setSummary(sp.getString("sttrace", "")); @@ -272,6 +274,9 @@ public class SettingsFragment extends PreferenceFragment SyncthingService.EXPORT_PATH), Toast.LENGTH_LONG).show(); } return true; + case SYNCTHING_RESET: + ((SyncthingActivity) getActivity()).getApi().resetSyncthing(getActivity()); + return true; default: return false; } diff --git a/src/main/java/com/nutomic/syncthingandroid/syncthing/RestApi.java b/src/main/java/com/nutomic/syncthingandroid/syncthing/RestApi.java index 74f7c57d..e6d5d321 100644 --- a/src/main/java/com/nutomic/syncthingandroid/syncthing/RestApi.java +++ b/src/main/java/com/nutomic/syncthingandroid/syncthing/RestApi.java @@ -379,6 +379,33 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener, .show(); } + /** + * Reset Syncthing's indexes when confirmed by a dialog. + */ + @TargetApi(11) + public void resetSyncthing(final Activity activity) { + final Intent intent = new Intent(mContext, SyncthingService.class) + .setAction(SyncthingService.ACTION_RESET); + + AlertDialog.Builder builder = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) + ? new AlertDialog.Builder(activity, AlertDialog.THEME_HOLO_LIGHT) + : new AlertDialog.Builder(activity); + builder.setTitle(R.string.streset_title); + builder.setMessage(R.string.streset_question) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + mContext.startService(intent); + Toast.makeText(activity, R.string.streset_done, Toast.LENGTH_LONG).show(); + } + }) + .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { } + }) + .show(); + } + /** * Creates a notification prompting the user to restart the app. */ diff --git a/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingRunnable.java b/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingRunnable.java index 7aaab30a..aa612441 100644 --- a/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingRunnable.java +++ b/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingRunnable.java @@ -27,18 +27,52 @@ public class SyncthingRunnable implements Runnable { private static final String TAG_NATIVE = "SyncthingNativeCode"; + public static final String UNIT_TEST_PATH = "was running"; + private final Context mContext; + private boolean mGenerate; + private String mCommand; + public enum Command { + generate, // Generate keys, a config file and immediately exit. + main, // Run the main Syncthing application. + reset, // Reset Syncthing's indexes + } + /** * Constructs instance. * - * @param command The exact command to be executed on the shell. + * @param command Which type of Syncthing command to execute. */ - public SyncthingRunnable(Context context, String command) { + public SyncthingRunnable(Context context, Command command) { mContext = context; - mCommand = command; + String syncthing = mContext.getApplicationInfo().dataDir + "/" + SyncthingService.BINARY_NAME; + switch (command) { + case generate: + mCommand = syncthing + " -generate='" + mContext.getFilesDir() + "' -no-browser"; + break; + case main: + mCommand = syncthing + " -home='" + mContext.getFilesDir() + "' -no-browser"; + break; + case reset: + mCommand = syncthing + " -home='" + mContext.getFilesDir() + "' -reset"; + break; + default: + Log.w(TAG, "Unknown command option"); + mCommand = ""; + } + } + + /** + * Constructs instance. + * + * @param manualCommand The exact command to be executed on the shell. Used for tests only. + */ + public SyncthingRunnable(Context context, String manualCommand) { + mContext = context; + mCommand = manualCommand; } @Override @@ -48,7 +82,7 @@ public class SyncthingRunnable implements Runnable { int ret = 1; Process process = null; try { - // Loop to handle syncthing restarts (these always have an error code of 3). + // Loop to handle Syncthing restarts (these always have an error code of 3). do { ProcessBuilder pb = new ProcessBuilder("sh"); Map env = pb.environment(); @@ -62,9 +96,13 @@ public class SyncthingRunnable implements Runnable { process = pb.start(); dos = new DataOutputStream(process.getOutputStream()); - // Call syncthing with -home (as it would otherwise use "~/.config/syncthing/". - dos.writeBytes(mCommand + " -home " + mContext.getFilesDir() + "\n"); - dos.writeBytes("exit\n"); + // Set (Android) home directory to data folder for syncthing to use. + dos.writeBytes("HOME=" + Environment.getExternalStorageDirectory() + " "); + dos.writeBytes("STTRACE=" + pm.getString("sttrace", "") + " "); + dos.writeBytes("STNORESTART=1 "); + dos.writeBytes("STNOUPGRADE=1 "); + dos.writeBytes(mCommand); + dos.writeBytes("\nexit\n"); dos.flush(); log(process.getInputStream(), Log.INFO); diff --git a/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java b/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java index 57653c77..8ed220c8 100644 --- a/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java +++ b/src/main/java/com/nutomic/syncthingandroid/syncthing/SyncthingService.java @@ -45,10 +45,16 @@ public class SyncthingService extends Service { private static final String TAG = "SyncthingService"; /** - * Intent action to perform a syncthing restart. + * Intent action to perform a Syncthing restart. */ public static final String ACTION_RESTART = "restart"; + /** + * Intent action to reset Syncthing's database. + */ + public static final String ACTION_RESET = "reset"; + + /** * Interval in ms at which the GUI is updated (eg {@link com.nutomic.syncthingandroid.fragments.DrawerFragment}). */ @@ -150,8 +156,12 @@ public class SyncthingService extends Service { mApi.shutdown(); mCurrentState = State.INIT; updateState(); - } - else if (mCurrentState != State.INIT) { + } else if (ACTION_RESET.equals(intent.getAction())) { + mApi.shutdown(); + new SyncthingRunnable(this, SyncthingRunnable.Command.reset).run(); + mCurrentState = State.INIT; + updateState(); + } else if (mCurrentState != State.INIT) { mDeviceStateHolder.update(intent); updateState(); } @@ -200,8 +210,7 @@ public class SyncthingService extends Service { mCurrentState = State.STARTING; registerOnWebGuiAvailableListener(mApi); new PollWebGuiAvailableTaskImpl(getFilesDir() + "/" + HTTPS_CERT_FILE).execute(mConfig.getWebGuiUrl()); - new Thread(new SyncthingRunnable( - this, getApplicationInfo().dataDir + "/" + BINARY_NAME)).start(); + new Thread(new SyncthingRunnable(this, SyncthingRunnable.Command.main)).start(); Notification n = new NotificationCompat.Builder(this) .setContentTitle(getString(R.string.syncthing_active)) .setSmallIcon(R.drawable.ic_stat_notify) diff --git a/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java b/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java index 061be894..a05d8366 100644 --- a/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java +++ b/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java @@ -78,9 +78,7 @@ public class ConfigXml { } private void generateKeysConfig(Context context) { - new SyncthingRunnable(context, context.getApplicationInfo().dataDir + "/" + - SyncthingService.BINARY_NAME + " -generate='" + context.getFilesDir() + "'") - .run(); + new SyncthingRunnable(context, SyncthingRunnable.Command.generate).run(); } public static File getConfigFile(Context context) { diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 719e611d..12231906 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -286,6 +286,17 @@ Please report any problems you encounter via Github. Characters : and \' are not allowed in password + + Reset Database + + + This action should only be performed based on a recommendation from our support team. + \nAre you sure you want to clear Syncthing\'s index database? + + + + Successfully reset Syncthing\'s database + About diff --git a/src/main/res/xml/app_settings.xml b/src/main/res/xml/app_settings.xml index 1726224c..fe49cbde 100644 --- a/src/main/res/xml/app_settings.xml +++ b/src/main/res/xml/app_settings.xml @@ -115,6 +115,11 @@ android:title="@string/sttrace_title" android:singleLine="true" /> + +