aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AndroidStyle.xml7
-rw-r--r--app/src/main/java/com/anysoftkeyboard/prefs/GlobalPrefsBackup.java112
-rw-r--r--app/src/main/java/com/anysoftkeyboard/ui/settings/MainFragment.java17
-rw-r--r--app/src/main/java/com/anysoftkeyboard/ui/settings/MainTweaksFragment.java171
-rw-r--r--app/src/main/java/com/anysoftkeyboard/ui/settings/UiTweaksFragment.java38
-rw-r--r--app/src/main/res/menu/main_fragment_menu.xml10
-rw-r--r--app/src/main/res/menu/main_tweaks_menu.xml9
-rw-r--r--app/src/main/res/values/ids.xml2
-rw-r--r--app/src/main/res/values/strings.xml3
-rw-r--r--app/src/main/res/xml/prefs_main_tweaks.xml39
-rw-r--r--app/src/main/res/xml/prefs_ui_tweaks.xml102
-rw-r--r--app/src/test/java/com/anysoftkeyboard/ViewTestUtils.java16
-rw-r--r--app/src/test/java/com/anysoftkeyboard/prefs/GlobalPrefsBackupTest.java148
-rw-r--r--app/src/test/java/com/anysoftkeyboard/ui/settings/BaseSettingsFragmentTest.java14
-rw-r--r--app/src/test/java/com/anysoftkeyboard/ui/settings/LanguageSettingsFragmentTest.java7
-rw-r--r--app/src/test/java/com/anysoftkeyboard/ui/settings/MainFragmentTest.java19
-rw-r--r--app/src/test/java/com/anysoftkeyboard/ui/settings/MainTweaksFragmentTest.java88
-rw-r--r--app/src/test/java/com/anysoftkeyboard/ui/settings/UserInterfaceSettingsFragmentTest.java7
-rw-r--r--build.gradle2
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin54334 -> 54334 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties3
-rw-r--r--prefs/src/main/java/com/anysoftkeyboard/prefs/RxSharedPrefs.java4
-rw-r--r--prefs/src/main/java/com/anysoftkeyboard/prefs/backup/PrefItem.java4
23 files changed, 669 insertions, 153 deletions
diff --git a/AndroidStyle.xml b/AndroidStyle.xml
index 7b3a09ea6..2ee5e1f78 100644
--- a/AndroidStyle.xml
+++ b/AndroidStyle.xml
@@ -89,6 +89,9 @@
<option name="JD_KEEP_EMPTY_RETURN" value="false" />
<option name="JD_PRESERVE_LINE_FEEDS" value="true" />
</JavaCodeStyleSettings>
+ <MarkdownNavigatorCodeStyleSettings>
+ <option name="RIGHT_MARGIN" value="72" />
+ </MarkdownNavigatorCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
@@ -115,6 +118,9 @@
</extensions>
</Objective-C-extensions>
<XML>
+ <option name="XML_KEEP_LINE_BREAKS" value="false" />
+ <option name="XML_ALIGN_ATTRIBUTES" value="false" />
+ <option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<ADDITIONAL_INDENT_OPTIONS fileType="java">
@@ -138,6 +144,7 @@
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
+ <option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
diff --git a/app/src/main/java/com/anysoftkeyboard/prefs/GlobalPrefsBackup.java b/app/src/main/java/com/anysoftkeyboard/prefs/GlobalPrefsBackup.java
new file mode 100644
index 000000000..8a646f6c5
--- /dev/null
+++ b/app/src/main/java/com/anysoftkeyboard/prefs/GlobalPrefsBackup.java
@@ -0,0 +1,112 @@
+package com.anysoftkeyboard.prefs;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.Pair;
+import android.support.v7.preference.PreferenceManager;
+
+import com.anysoftkeyboard.prefs.backup.PrefItem;
+import com.anysoftkeyboard.prefs.backup.PrefsProvider;
+import com.anysoftkeyboard.prefs.backup.PrefsRoot;
+import com.anysoftkeyboard.prefs.backup.PrefsXmlStorage;
+import com.menny.android.anysoftkeyboard.AnyApplication;
+import com.menny.android.anysoftkeyboard.R;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import io.reactivex.Observable;
+import io.reactivex.ObservableSource;
+import io.reactivex.functions.BiConsumer;
+import io.reactivex.functions.BiFunction;
+import io.reactivex.functions.Function;
+
+public class GlobalPrefsBackup {
+ @VisibleForTesting
+ static final String GLOBAL_BACKUP_FILENAME = "AnySoftKeyboardPrefs.xml";
+
+ public static List<ProviderDetails> getAllPrefsProviders(@NonNull Context context) {
+ return Arrays.asList(
+ new ProviderDetails(
+ new RxSharedPrefs.SharedPrefsProvider(PreferenceManager.getDefaultSharedPreferences(context)),
+ R.string.shared_prefs_provider_name));
+ }
+
+
+ private static Boolean backupProvider(PrefsProvider provider, PrefsRoot prefsRoot) {
+ final PrefsRoot providerRoot = provider.getPrefsRoot();
+ prefsRoot.createChild()
+ .addValue("providerId", provider.providerId())
+ .addValue("version", Integer.toString(providerRoot.getVersion()))
+ .addChild(providerRoot);
+
+ return Boolean.TRUE;
+ }
+
+ private static Boolean restoreProvider(PrefsProvider provider, PrefsRoot prefsRoot) {
+ Observable.fromIterable(prefsRoot.getChildren())
+ .filter(prefItem -> provider.providerId().equals(prefItem.getValue("providerId")))
+ .blockingSubscribe(providerPrefItem -> {
+ PrefsRoot prefsRootForProvider = new PrefsRoot(Integer.parseInt(providerPrefItem.getValue("version")));
+ final PrefItem actualPrefRoot = providerPrefItem.getChildren().iterator().next();
+ for (Map.Entry<String, String> attribute : actualPrefRoot.getValues()) {
+ prefsRootForProvider.addValue(attribute.getKey(), attribute.getValue());
+ }
+ for (PrefItem child : actualPrefRoot.getChildren()) {
+ prefsRootForProvider.addChild(child);
+ }
+
+ provider.storePrefsRoot(prefsRootForProvider);
+ });
+
+ return Boolean.TRUE;
+ }
+
+ @NonNull
+ public static Observable<Boolean> backup(Observable<Pair<List<ProviderDetails>, Boolean[]>> enabledProvidersObservable) {
+ return doIt(enabledProvidersObservable, GlobalPrefsBackup::backupProvider, s -> new PrefsRoot(1), PrefsXmlStorage::store);
+ }
+
+ @NonNull
+ public static Observable<Boolean> restore(Observable<Pair<List<ProviderDetails>, Boolean[]>> enabledProvidersObservable) {
+ return doIt(enabledProvidersObservable, GlobalPrefsBackup::restoreProvider, PrefsXmlStorage::load, (s, p) -> { /*no-op*/ });
+ }
+
+ @NonNull
+ private static Observable<Boolean> doIt(
+ Observable<Pair<List<ProviderDetails>, Boolean[]>> enabledProvidersObservable,
+ BiFunction<PrefsProvider, PrefsRoot, Boolean> providerAction,
+ Function<PrefsXmlStorage, PrefsRoot> prefsRootFactory,
+ BiConsumer<PrefsXmlStorage, PrefsRoot> prefsRootFinalizer) {
+
+ final Observable<PrefsProvider> providersObservable = enabledProvidersObservable
+ .flatMap((Function<Pair<List<ProviderDetails>, Boolean[]>, ObservableSource<Pair<ProviderDetails, Boolean>>>) pair -> Observable.zip(
+ Observable.fromIterable(pair.first),
+ Observable.fromArray(pair.second),
+ Pair::new
+ ))
+ .filter(pair -> pair.second)
+ .map(pair -> pair.first.provider);
+
+ final PrefsXmlStorage storage = new PrefsXmlStorage(AnyApplication.getBackupFile(GLOBAL_BACKUP_FILENAME));
+
+ return Observable.using(() -> prefsRootFactory.apply(storage),
+ prefsRoot -> providersObservable.map(provider -> providerAction.apply(provider, prefsRoot)),
+ prefsRoot -> prefsRootFinalizer.accept(storage, prefsRoot));
+ }
+
+ public static class ProviderDetails {
+ public final PrefsProvider provider;
+ @StringRes
+ public final int providerTitle;
+
+ @VisibleForTesting
+ ProviderDetails(PrefsProvider provider, @StringRes int providerTitle) {
+ this.provider = provider;
+ this.providerTitle = providerTitle;
+ }
+ }
+}
diff --git a/app/src/main/java/com/anysoftkeyboard/ui/settings/MainFragment.java b/app/src/main/java/com/anysoftkeyboard/ui/settings/MainFragment.java
index 7931f7aa9..cbbad2c1e 100644
--- a/app/src/main/java/com/anysoftkeyboard/ui/settings/MainFragment.java
+++ b/app/src/main/java/com/anysoftkeyboard/ui/settings/MainFragment.java
@@ -11,7 +11,6 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
-import android.support.v4.view.MenuItemCompat;
import android.support.v7.graphics.Palette;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
@@ -92,20 +91,20 @@ public class MainFragment extends Fragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ inflater.inflate(R.menu.main_fragment_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
- final MenuItem aboutMenuItem = menu.add(0, R.id.about_menu_option, Menu.FIRST, R.string.menu_about_item)
- .setIcon(R.drawable.ic_menu_action_about)
- .setVisible(true);
- MenuItemCompat.setShowAsAction(aboutMenuItem, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ FragmentChauffeurActivity activity = (FragmentChauffeurActivity) getActivity();
switch (item.getItemId()) {
case R.id.about_menu_option:
- FragmentChauffeurActivity activity = (FragmentChauffeurActivity) getActivity();
activity.addFragmentToUi(new AboutAnySoftKeyboardFragment(), TransitionExperiences.DEEPER_EXPERIENCE_TRANSITION);
return true;
+ case R.id.tweaks_menu_option:
+ activity.addFragmentToUi(new MainTweaksFragment(), TransitionExperiences.DEEPER_EXPERIENCE_TRANSITION);
+ return true;
default:
return super.onOptionsItemSelected(item);
}
@@ -182,8 +181,9 @@ public class MainFragment extends Fragment {
mDemoAnyKeyboardView.setOnViewBitmapReadyListener(this::onDemoViewBitmapReady);
- if (mNotConfiguredAnimation != null)
+ if (mNotConfiguredAnimation != null) {
mNotConfiguredAnimation.start();
+ }
}
private void onDemoViewBitmapReady(Bitmap demoViewBitmap) {
@@ -193,8 +193,9 @@ public class MainFragment extends Fragment {
Palette p = Palette.from(bitmap).generate();
Palette.Swatch highestSwatch = null;
for (Palette.Swatch swatch : p.getSwatches()) {
- if (highestSwatch == null || highestSwatch.getPopulation() < swatch.getPopulation())
+ if (highestSwatch == null || highestSwatch.getPopulation() < swatch.getPopulation()) {
highestSwatch = swatch;
+ }
}
return highestSwatch;
})
diff --git a/app/src/main/java/com/anysoftkeyboard/ui/settings/MainTweaksFragment.java b/app/src/main/java/com/anysoftkeyboard/ui/settings/MainTweaksFragment.java
new file mode 100644
index 000000000..f5de86481
--- /dev/null
+++ b/app/src/main/java/com/anysoftkeyboard/ui/settings/MainTweaksFragment.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2013 Menny Even-Danan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.anysoftkeyboard.ui.settings;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.Pair;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.anysoftkeyboard.prefs.GlobalPrefsBackup;
+import com.anysoftkeyboard.rx.RxSchedulers;
+import com.anysoftkeyboard.ui.GeneralDialogController;
+import com.anysoftkeyboard.ui.dev.DeveloperToolsFragment;
+import com.menny.android.anysoftkeyboard.R;
+
+import net.evendanan.chauffeur.lib.FragmentChauffeurActivity;
+import net.evendanan.chauffeur.lib.experiences.TransitionExperiences;
+import net.evendanan.pushingpixels.RxProgressDialog;
+
+import java.util.List;
+
+import io.reactivex.Observable;
+import io.reactivex.disposables.CompositeDisposable;
+
+public class MainTweaksFragment extends PreferenceFragmentCompat {
+
+ @VisibleForTesting
+ static final String DEV_TOOLS_KEY = "dev_tools";
+
+ private static final int FAILED_DIALOG = 10;
+ private static final int SUCCESS_DIALOG = 20;
+
+ private GeneralDialogController mDialogController;
+ @NonNull
+ private CompositeDisposable mDisposable = new CompositeDisposable();
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.prefs_main_tweaks);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mDialogController = new GeneralDialogController(getActivity(), this::onSetupDialogRequired);
+
+ Preference preference = findPreference(DEV_TOOLS_KEY);
+ if (preference == null) {
+ throw new NullPointerException("Preference with key '" + DEV_TOOLS_KEY + "' was not found in resource " + R.xml.prefs_main_tweaks);
+ } else {
+ preference.setOnPreferenceClickListener(this::onDevToolsPreferenceClicked);
+ }
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.main_tweaks_menu, menu);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ MainSettingsActivity.setActivityTitle(this, getString(R.string.tweaks_group));
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ mDialogController.dismiss();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.backup_prefs:
+ case R.id.restore_prefs:
+ mDialogController.showDialog(item.getItemId());
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private void onSetupDialogRequired(AlertDialog.Builder builder, int optionId, Object data) {
+ final int actionString;
+ final boolean backup;
+ switch (optionId) {
+ case R.id.backup_prefs:
+ backup = true;
+ actionString = R.string.word_editor_action_backup_words;
+ builder.setMessage(R.string.pick_prefs_providers_to_backup);
+ break;
+ case R.id.restore_prefs:
+ backup = false;
+ actionString = R.string.word_editor_action_restore_words;
+ builder.setMessage(R.string.pick_prefs_providers_to_restore);
+ break;
+ default:
+ throw new IllegalArgumentException("The option-id " + optionId + " is not supported here.");
+ }
+
+ final List<GlobalPrefsBackup.ProviderDetails> supportedProviders = GlobalPrefsBackup.getAllPrefsProviders(getContext());
+ final CharSequence[] providersTitles = new CharSequence[supportedProviders.size()];
+ final boolean[] initialChecked = new boolean[supportedProviders.size()];
+ final Boolean[] checked = new Boolean[supportedProviders.size()];
+
+ for (int providerIndex = 0; providerIndex < supportedProviders.size(); providerIndex++) {
+ //starting with everything checked
+ checked[providerIndex] = initialChecked[providerIndex] = true;
+ providersTitles[providerIndex] = getText(supportedProviders.get(providerIndex).providerTitle);
+ }
+
+ builder.setMultiChoiceItems(providersTitles, initialChecked, (dialogInterface, i, b) -> checked[i] = b);
+ builder.setNegativeButton(android.R.string.cancel, null);
+ builder.setCancelable(true);
+ builder.setTitle(actionString);
+ builder.setPositiveButton(actionString, (dialog, which) -> {
+ mDisposable.dispose();
+ mDisposable = new CompositeDisposable();
+
+
+ final Observable<Pair<List<GlobalPrefsBackup.ProviderDetails>, Boolean[]>> dialogObservable =
+ RxProgressDialog.create(new Pair<>(supportedProviders, checked), getActivity(), getText(R.string.take_a_while_progress_message))
+ .subscribeOn(RxSchedulers.background());
+
+ final Observable<Boolean> prefsOperationObservable = backup ? GlobalPrefsBackup.backup(dialogObservable) : GlobalPrefsBackup.restore(dialogObservable);
+
+ mDisposable.add(prefsOperationObservable
+ .lastOrError()
+ .observeOn(RxSchedulers.mainThread())
+ .subscribe(
+ lastBoolean -> mDialogController.showDialog(SUCCESS_DIALOG),
+ e -> mDialogController.showDialog(FAILED_DIALOG, e)));
+ });
+ }
+
+ private boolean onDevToolsPreferenceClicked(Preference p) {
+ Activity activity = getActivity();
+ if (activity != null && activity instanceof FragmentChauffeurActivity) {
+ ((FragmentChauffeurActivity) activity).addFragmentToUi(new DeveloperToolsFragment(), TransitionExperiences.DEEPER_EXPERIENCE_TRANSITION);
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/app/src/main/java/com/anysoftkeyboard/ui/settings/UiTweaksFragment.java b/app/src/main/java/com/anysoftkeyboard/ui/settings/UiTweaksFragment.java
index 5f50f2a8f..275c185cf 100644
--- a/app/src/main/java/com/anysoftkeyboard/ui/settings/UiTweaksFragment.java
+++ b/app/src/main/java/com/anysoftkeyboard/ui/settings/UiTweaksFragment.java
@@ -16,22 +16,12 @@
package com.anysoftkeyboard.ui.settings;
-import android.app.Activity;
import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
-import android.view.View;
-import com.anysoftkeyboard.ui.dev.DeveloperToolsFragment;
import com.menny.android.anysoftkeyboard.R;
-import net.evendanan.chauffeur.lib.FragmentChauffeurActivity;
-import net.evendanan.chauffeur.lib.experiences.TransitionExperiences;
-
-public class UiTweaksFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener {
-
- public static final String DEV_TOOLS_KEY = "dev_tools";
+public class UiTweaksFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@@ -39,35 +29,9 @@ public class UiTweaksFragment extends PreferenceFragmentCompat implements Prefer
}
@Override
- public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- Preference preference = findPreference(DEV_TOOLS_KEY);
- if (preference == null) {
- throw new NullPointerException("Preference with key '" + DEV_TOOLS_KEY + "' was not found in resource " + R.xml.prefs_ui_tweaks);
- } else {
- preference.setOnPreferenceClickListener(this);
- }
- }
-
- @Override
public void onStart() {
super.onStart();
MainSettingsActivity.setActivityTitle(this, getString(R.string.tweaks_group));
}
- @Override
- public boolean onPreferenceClick(Preference preference) {
- switch (preference.getKey()) {
- case DEV_TOOLS_KEY:
- Activity activity = getActivity();
- if (activity != null && activity instanceof FragmentChauffeurActivity) {
- ((FragmentChauffeurActivity) activity).addFragmentToUi(new DeveloperToolsFragment(), TransitionExperiences.DEEPER_EXPERIENCE_TRANSITION);
- return true;
- }
- return true;
-
- default:
- return false;
- }
- }
}
diff --git a/app/src/main/res/menu/main_fragment_menu.xml b/app/src/main/res/menu/main_fragment_menu.xml
new file mode 100644
index 000000000..02e398b5b
--- /dev/null
+++ b/app/src/main/res/menu/main_fragment_menu.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item android:id="@+id/about_menu_option" android:icon="@drawable/ic_menu_action_about"
+ android:title="@string/menu_about_item" app:showAsAction="ifRoom|never" />
+
+ <item android:id="@+id/tweaks_menu_option" android:icon="@drawable/ic_action_settings_light"
+ android:title="@string/tweaks_group" app:showAsAction="never|withText" />
+</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/main_tweaks_menu.xml b/app/src/main/res/menu/main_tweaks_menu.xml
new file mode 100644
index 000000000..4a8327c67
--- /dev/null
+++ b/app/src/main/res/menu/main_tweaks_menu.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item android:id="@+id/backup_prefs" android:icon="@android:drawable/ic_menu_save"
+ android:title="@string/word_editor_action_backup_words" app:showAsAction="never|withText" />
+ <item android:id="@+id/restore_prefs" android:icon="@android:drawable/ic_menu_upload"
+ android:title="@string/word_editor_action_restore_words"
+ app:showAsAction="never|withText" />
+</menu> \ No newline at end of file
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
index 2023b44c8..0d4b6ff20 100644
--- a/app/src/main/res/values/ids.xml
+++ b/app/src/main/res/values/ids.xml
@@ -16,6 +16,4 @@
<item name="notification_icon_debug_version" type="id" />
<item name="notification_icon_app_error" type="id" />
-
- <item name="about_menu_option" type="id" />
</resources> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7f083d460..ae6864dd3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -708,4 +708,7 @@
<string name="theme_case_type_override_title">Keyboard letter-case override</string>
<string name="theme_case_type_override_summary">How to determine letters-case in the keyboard view. Currently, %s</string>
<string name="take_a_while_progress_message">This might take a while…</string>
+ <string name="shared_prefs_provider_name">App Settings</string>
+ <string name="pick_prefs_providers_to_backup">What would you like to backup?</string>
+ <string name="pick_prefs_providers_to_restore">What would you like to restore?</string>
</resources>
diff --git a/app/src/main/res/xml/prefs_main_tweaks.xml b/app/src/main/res/xml/prefs_main_tweaks.xml
new file mode 100644
index 000000000..6792e8420
--- /dev/null
+++ b/app/src/main/res/xml/prefs_main_tweaks.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v7.preference.PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android" android:key="tweaks_group_screen"
+ android:title="@string/tweaks_group">
+
+ <android.support.v7.preference.ListPreference
+ android:defaultValue="@string/settings_default_force_locale_setting"
+ android:dialogTitle="@string/settings_force_locale_title"
+ android:entries="@array/settings_key_force_locale_values"
+ android:entryValues="@array/settings_key_force_locale_values"
+ android:key="@string/settings_key_force_locale"
+ android:summary="@string/settings_force_locale_summary"
+ android:title="@string/settings_force_locale_title" />
+
+ <android.support.v7.preference.CheckBoxPreference
+ android:defaultValue="@bool/settings_default_keyboard_icon_in_status_bar"
+ android:key="@string/settings_key_keyboard_icon_in_status_bar" android:persistent="true"
+ android:summaryOff="@string/show_keyboard_icon_in_status_bar_off_summary"
+ android:summaryOn="@string/show_keyboard_icon_in_status_bar_on_summary"
+ android:title="@string/show_keyboard_icon_in_status_bar_title" />
+
+ <android.support.v7.preference.CheckBoxPreference
+ android:defaultValue="@bool/settings_default_show_settings_app"
+ android:key="@string/settings_key_show_settings_app" android:persistent="true"
+ android:summaryOff="@string/settings_key_show_settings_app_off_summary"
+ android:summaryOn="@string/settings_key_show_settings_app_on_summary"
+ android:title="@string/show_settings_app_in_launcher" />
+
+ <android.support.v7.preference.CheckBoxPreference
+ android:defaultValue="@bool/settings_default_show_chewbacca"
+ android:key="@string/settings_key_show_chewbacca" android:persistent="true"
+ android:summaryOff="@string/show_crash_notification_off_summary"
+ android:summaryOn="@string/show_crash_notification_on_summary"
+ android:title="@string/show_crash_notification" />
+
+ <Preference android:key="dev_tools"
+ android:summary="@string/click_for_developer_features_summary"
+ android:title="@string/click_for_developer_features" />
+</android.support.v7.preference.PreferenceScreen> \ No newline at end of file
diff --git a/app/src/main/res/xml/prefs_ui_tweaks.xml b/app/src/main/res/xml/prefs_ui_tweaks.xml
index 5c7b25ee8..1b1a5af0d 100644
--- a/app/src/main/res/xml/prefs_ui_tweaks.xml
+++ b/app/src/main/res/xml/prefs_ui_tweaks.xml
@@ -1,87 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
-<android.support.v7.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:pp="http://schemas.android.com/apk/res-auto"
- android:key="tweaks_group_screen"
+<android.support.v7.preference.PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:pp="http://schemas.android.com/apk/res-auto" android:key="tweaks_group_screen"
android:title="@string/tweaks_group">
- <android.support.v7.preference.PreferenceCategory
- android:key="tweak_sound_group"
+ <android.support.v7.preference.PreferenceCategory android:key="tweak_sound_group"
android:title="@string/tweak_sound_group">
- <android.support.v7.preference.CheckBoxPreference
- android:defaultValue="false"
- android:key="use_custom_sound_volume"
- android:persistent="true"
+ <android.support.v7.preference.CheckBoxPreference android:defaultValue="false"
+ android:key="use_custom_sound_volume" android:persistent="true"
android:summaryOff="@string/use_custom_sound_volume_off_summary"
android:summaryOn="@string/use_custom_sound_volume_on_summary"
android:title="@string/use_custom_sound_volume" />
<!-- Using this import require an Android Library reference from https://github.com/menny/PushingPixels -->
<net.evendanan.pushingpixels.SlidePreference
android:defaultValue="@integer/settings_default_custom_volume_level"
- android:dependency="use_custom_sound_volume"
- android:key="custom_sound_volume"
- android:persistent="true"
- android:title="@string/custom_sound_volume"
+ android:dependency="use_custom_sound_volume" android:key="custom_sound_volume"
+ android:persistent="true" android:title="@string/custom_sound_volume"
pp:slideMaximum="@integer/settings_custom_volume_level_slide_max"
pp:slideMinimum="@integer/settings_custom_volume_level_slide_min" />
</android.support.v7.preference.PreferenceCategory>
- <android.support.v7.preference.PreferenceCategory
- android:key="tweak_ui_group"
+ <android.support.v7.preference.PreferenceCategory android:key="tweak_ui_group"
android:title="@string/tweak_ui_group">
- <android.support.v7.preference.ListPreference
- android:defaultValue="@string/settings_default_force_locale_setting"
- android:dialogTitle="@string/settings_force_locale_title"
- android:entries="@array/settings_key_force_locale_values"
- android:entryValues="@array/settings_key_force_locale_values"
- android:key="@string/settings_key_force_locale"
- android:summary="@string/settings_force_locale_summary"
- android:title="@string/settings_force_locale_title" />
-
- <android.support.v7.preference.CheckBoxPreference
- android:defaultValue="@bool/settings_default_keyboard_icon_in_status_bar"
- android:key="@string/settings_key_keyboard_icon_in_status_bar"
- android:persistent="true"
- android:summaryOff="@string/show_keyboard_icon_in_status_bar_off_summary"
- android:summaryOn="@string/show_keyboard_icon_in_status_bar_on_summary"
- android:title="@string/show_keyboard_icon_in_status_bar_title" />
-
<android.support.v7.preference.CheckBoxPreference
android:defaultValue="@bool/settings_default_extension_keyboard_enabled"
- android:key="@string/settings_key_extension_keyboard_enabled"
- android:persistent="true"
+ android:key="@string/settings_key_extension_keyboard_enabled" android:persistent="true"
android:summaryOff="@string/extension_keyboard_enabled_off_summary"
android:summaryOn="@string/extension_keyboard_enabled_on_summary"
android:title="@string/is_extesion_keyboard_above_keyboard" />
<android.support.v7.preference.CheckBoxPreference
android:defaultValue="@bool/settings_default_is_sticky_extesion_keyboard"
- android:key="@string/settings_key_is_sticky_extesion_keyboard"
- android:persistent="true"
+ android:key="@string/settings_key_is_sticky_extesion_keyboard" android:persistent="true"
android:summaryOff="@string/is_sticky_extesion_keyboard_off_summary"
android:summaryOn="@string/is_sticky_extesion_keyboard_on_summary"
android:title="@string/is_sticky_extesion_keyboard" />
<android.support.v7.preference.CheckBoxPreference
android:defaultValue="@bool/settings_default_portrait_fullscreen"
- android:key="@string/settings_key_portrait_fullscreen"
- android:persistent="true"
+ android:key="@string/settings_key_portrait_fullscreen" android:persistent="true"
android:summaryOff="@string/fullscreen_portrait_input_connection_supported_off_summary"
android:summaryOn="@string/fullscreen_portrait_input_connection_supported_on_summary"
android:title="@string/fullscreen_portrait_input_connection_supported" />
<android.support.v7.preference.CheckBoxPreference
android:defaultValue="@bool/settings_default_landscape_fullscreen"
- android:key="@string/settings_key_landscape_fullscreen"
- android:persistent="true"
+ android:key="@string/settings_key_landscape_fullscreen" android:persistent="true"
android:summaryOff="@string/fullscreen_input_connection_supported_off_summary"
android:summaryOn="@string/fullscreen_input_connection_supported_on_summary"
android:title="@string/fullscreen_input_connection_supported" />
</android.support.v7.preference.PreferenceCategory>
- <android.support.v7.preference.PreferenceCategory
- android:key="tweak_ux_group"
+ <android.support.v7.preference.PreferenceCategory android:key="tweak_ux_group"
android:title="@string/tweak_ux_group">
<android.support.v7.preference.ListPreference
@@ -104,27 +76,19 @@
<android.support.v7.preference.CheckBoxPreference
android:defaultValue="@bool/settings_default_lang_key_shows_popup"
- android:key="@string/settings_key_lang_key_shows_popup"
- android:persistent="true"
+ android:key="@string/settings_key_lang_key_shows_popup" android:persistent="true"
android:summaryOff="@string/lang_key_shows_popup_off_summary"
android:summaryOn="@string/lang_key_shows_popup_on_summary"
android:title="@string/lang_key_shows_popup" />
- <EditTextPreference
- android:autoText="false"
- android:capitalize="none"
- android:defaultValue=".com"
- android:dialogTitle="@string/default_domain_text"
- android:key="default_domain_text"
- android:lines="1"
- android:persistent="true"
- android:singleLine="true"
- android:title="@string/default_domain_text" />
+ <EditTextPreference android:autoText="false" android:capitalize="none"
+ android:defaultValue=".com" android:dialogTitle="@string/default_domain_text"
+ android:key="default_domain_text" android:lines="1" android:persistent="true"
+ android:singleLine="true" android:title="@string/default_domain_text" />
<android.support.v7.preference.CheckBoxPreference
android:defaultValue="@bool/settings_default_always_hide_language_key"
- android:key="@string/settings_key_always_hide_language_key"
- android:persistent="true"
+ android:key="@string/settings_key_always_hide_language_key" android:persistent="true"
android:summaryOff="@string/always_hide_language_key_off_summary"
android:summaryOn="@string/always_hide_language_key_on_summary"
android:title="@string/always_hide_language_key" />
@@ -148,37 +112,15 @@
android:title="@string/settings_split_state_title_landscape" />
</android.support.v7.preference.PreferenceCategory>
- <android.support.v7.preference.PreferenceCategory
- android:key="tweak_workarounds_group"
+ <android.support.v7.preference.PreferenceCategory android:key="tweak_workarounds_group"
android:title="@string/tweak_workarounds_group">
<android.support.v7.preference.CheckBoxPreference
android:defaultValue="@bool/settings_default_workaround_disable_rtl_fix"
- android:key="@string/settings_key_workaround_disable_rtl_fix"
- android:persistent="true"
+ android:key="@string/settings_key_workaround_disable_rtl_fix" android:persistent="true"
android:summaryOff="@string/workaround_disable_rtl_fix_summary_off"
android:summaryOn="@string/workaround_disable_rtl_fix_summary_on"
android:title="@string/workaround_disable_rtl_fix" />
</android.support.v7.preference.PreferenceCategory>
- <android.support.v7.preference.CheckBoxPreference
- android:defaultValue="@bool/settings_default_show_settings_app"
- android:key="@string/settings_key_show_settings_app"
- android:persistent="true"
- android:summaryOff="@string/settings_key_show_settings_app_off_summary"
- android:summaryOn="@string/settings_key_show_settings_app_on_summary"
- android:title="@string/show_settings_app_in_launcher" />
-
- <android.support.v7.preference.CheckBoxPreference
- android:defaultValue="@bool/settings_default_show_chewbacca"
- android:key="@string/settings_key_show_chewbacca"
- android:persistent="true"
- android:summaryOff="@string/show_crash_notification_off_summary"
- android:summaryOn="@string/show_crash_notification_on_summary"
- android:title="@string/show_crash_notification" />
-
- <Preference
- android:key="dev_tools"
- android:summary="@string/click_for_developer_features_summary"
- android:title="@string/click_for_developer_features"/>
</android.support.v7.preference.PreferenceScreen> \ No newline at end of file
diff --git a/app/src/test/java/com/anysoftkeyboard/ViewTestUtils.java b/app/src/test/java/com/anysoftkeyboard/ViewTestUtils.java
index f684195a1..49fea5ca1 100644
--- a/app/src/test/java/com/anysoftkeyboard/ViewTestUtils.java
+++ b/app/src/test/java/com/anysoftkeyboard/ViewTestUtils.java
@@ -2,17 +2,22 @@ package com.anysoftkeyboard;
import android.graphics.Point;
import android.os.SystemClock;
+import android.support.annotation.NonNull;
+import android.support.v4.app.Fragment;
import android.support.v7.preference.Preference;
import android.view.MotionEvent;
import android.view.View;
import com.anysoftkeyboard.keyboards.Keyboard;
+import com.menny.android.anysoftkeyboard.R;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+import org.robolectric.Robolectric;
+import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowSystemClock;
import java.util.List;
@@ -75,6 +80,17 @@ public class ViewTestUtils {
return navigateFromTo(view, getKeyCenterPoint(start), getKeyCenterPoint(end), duration, alsoDown, alsoUp);
}
+ @NonNull
+ public static Fragment navigateByClicking(Fragment rootFragment, int viewToClick) {
+ final View viewById = rootFragment.getView().findViewById(viewToClick);
+ Assert.assertNotNull(viewById);
+ final View.OnClickListener onClickListener = Shadows.shadowOf(viewById).getOnClickListener();
+ Assert.assertNotNull(onClickListener);
+ onClickListener.onClick(viewById);
+ Robolectric.flushForegroundThreadScheduler();
+ return rootFragment.getActivity().getSupportFragmentManager().findFragmentById(R.id.main_ui_content);
+ }
+
@Test
public void testNavigateFromToHelpMethod() {
View view = Mockito.mock(View.class);
diff --git a/app/src/test/java/com/anysoftkeyboard/prefs/GlobalPrefsBackupTest.java b/app/src/test/java/com/anysoftkeyboard/prefs/GlobalPrefsBackupTest.java
new file mode 100644
index 000000000..73e090f22
--- /dev/null
+++ b/app/src/test/java/com/anysoftkeyboard/prefs/GlobalPrefsBackupTest.java
@@ -0,0 +1,148 @@
+package com.anysoftkeyboard.prefs;
+
+import android.support.annotation.Nullable;
+import android.support.v4.util.Pair;
+
+import com.anysoftkeyboard.AnySoftKeyboardRobolectricTestRunner;
+import com.anysoftkeyboard.base.Charsets;
+import com.anysoftkeyboard.prefs.backup.PrefItem;
+import com.anysoftkeyboard.prefs.backup.PrefsProvider;
+import com.anysoftkeyboard.prefs.backup.PrefsRoot;
+import com.anysoftkeyboard.test.TestUtils;
+import com.menny.android.anysoftkeyboard.AnyApplication;
+import com.menny.android.anysoftkeyboard.R;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import io.reactivex.Observable;
+
+@RunWith(AnySoftKeyboardRobolectricTestRunner.class)
+public class GlobalPrefsBackupTest {
+
+ static class FakePrefsProvider implements PrefsProvider {
+ private final String mId;
+ @Nullable
+ public PrefsRoot storedPrefsRoot;
+
+ FakePrefsProvider(String id) {
+
+ mId = id;
+ }
+
+ @Override
+ public PrefsRoot getPrefsRoot() {
+ PrefsRoot root = new PrefsRoot(2);
+ root.addValue("test", "value");
+ root.addValue("ctorId", mId);
+ root.createChild()
+ .addValue("child", "child-value");
+ return root;
+ }
+
+ @Override
+ public String providerId() {
+ return mId;
+ }
+
+ @Override
+ public void storePrefsRoot(PrefsRoot prefsRoot) {
+ storedPrefsRoot = prefsRoot;
+ }
+ }
+
+ @Test
+ public void testGetAllPrefsProviders() {
+ final List<GlobalPrefsBackup.ProviderDetails> allPrefsProviders = GlobalPrefsBackup.getAllPrefsProviders(RuntimeEnvironment.application);
+ Assert.assertNotNull(allPrefsProviders);
+ Assert.assertEquals(1, allPrefsProviders.size());
+ }
+
+ @Test
+ public void testBackupRestoreHappyPath() throws Exception {
+ final FakePrefsProvider fakePrefsProvider = new FakePrefsProvider("id1");
+ final PrefsRoot originalPrefsRoot = fakePrefsProvider.getPrefsRoot();
+ List<GlobalPrefsBackup.ProviderDetails> fakeDetails = Collections.singletonList(
+ new GlobalPrefsBackup.ProviderDetails(fakePrefsProvider, R.string.pop_text_type_title));
+
+ GlobalPrefsBackup.backup(Observable.just(Pair.create(fakeDetails, new Boolean[]{true})))
+ .blockingSubscribe(b -> { });
+
+ System.out.println("AnyApplication.getBackupFile(GlobalPrefsBackup.GLOBAL_BACKUP_FILENAME) is " + AnyApplication.getBackupFile(GlobalPrefsBackup.GLOBAL_BACKUP_FILENAME).getAbsolutePath());
+ System.out.println(Arrays.toString(Files.readAllLines(AnyApplication.getBackupFile(GlobalPrefsBackup.GLOBAL_BACKUP_FILENAME).toPath(), Charsets.UTF8).toArray()));
+ Assert.assertTrue(AnyApplication.getBackupFile(GlobalPrefsBackup.GLOBAL_BACKUP_FILENAME).exists());
+ Assert.assertTrue(AnyApplication.getBackupFile(GlobalPrefsBackup.GLOBAL_BACKUP_FILENAME).length() > 0);
+
+ Assert.assertNull(fakePrefsProvider.storedPrefsRoot);
+ GlobalPrefsBackup.restore(Observable.just(Pair.create(fakeDetails, new Boolean[]{true})))
+ .blockingSubscribe(b -> { });
+
+ Assert.assertNotNull(fakePrefsProvider.storedPrefsRoot);
+ Assert.assertNotSame(originalPrefsRoot, fakePrefsProvider.storedPrefsRoot);
+ assertRootsEqual(originalPrefsRoot, fakePrefsProvider.storedPrefsRoot);
+ }
+
+ @Test
+ public void testOnlyBackupRestoreEnabledProviders() {
+ List<GlobalPrefsBackup.ProviderDetails> fakesDetails = new ArrayList<>(5);
+ final FakePrefsProvider[] fakePrefsProviders = new FakePrefsProvider[5];
+ final PrefsRoot[] originalRoots = new PrefsRoot[fakePrefsProviders.length];
+ for (int providerIndex = 0; providerIndex < fakePrefsProviders.length; providerIndex++) {
+ fakePrefsProviders[providerIndex] = new FakePrefsProvider("id_" + providerIndex);
+ originalRoots[providerIndex] = fakePrefsProviders[providerIndex].getPrefsRoot();
+ fakesDetails.add(new GlobalPrefsBackup.ProviderDetails(fakePrefsProviders[providerIndex], R.string.pop_text_type_title));
+ }
+
+ final Boolean[] providersToBackup = {true, true, true, false, true};
+ GlobalPrefsBackup.backup(Observable.just(Pair.create(fakesDetails, providersToBackup)))
+ .blockingSubscribe(b -> { });
+
+ //restoring the first and last. Also asking for restore of the 4th, which is not in the list
+ final Boolean[] providersToRestore = {true, false, false, true, true};
+ GlobalPrefsBackup.restore(Observable.just(Pair.create(fakesDetails, providersToRestore)))
+ .blockingSubscribe(b -> { });
+
+ for (int providerIndex = 0; providerIndex < fakePrefsProviders.length; providerIndex++) {
+ final FakePrefsProvider fakePrefsProvider = fakePrefsProviders[providerIndex];
+ if (providersToRestore[providerIndex] && providersToBackup[providerIndex]) {
+ Assert.assertNotNull("Provider at index " + providerIndex + " should have been restored!", fakePrefsProvider.storedPrefsRoot);
+ Assert.assertNotSame("Provider at index " + providerIndex, originalRoots[providerIndex], fakePrefsProvider.storedPrefsRoot);
+ assertRootsEqual(originalRoots[providerIndex], fakePrefsProvider.storedPrefsRoot);
+ } else {
+ Assert.assertNull("Provider at index " + providerIndex, fakePrefsProvider.storedPrefsRoot);
+ }
+ }
+ }
+
+ public static void assertRootsEqual(PrefsRoot root1, PrefsRoot root2) {
+ Assert.assertEquals(root1.getVersion(), root2.getVersion());
+
+ assertPrefItemsEqual(root1, root2);
+ }
+
+ public static void assertPrefItemsEqual(PrefItem prefItem1, PrefItem prefItem2) {
+ for (Map.Entry<String, String> values : prefItem1.getValues()) {
+ Assert.assertEquals(values.getValue(), prefItem2.getValue(values.getKey()));
+ }
+
+ for (Map.Entry<String, String> values : prefItem2.getValues()) {
+ Assert.assertEquals(values.getValue(), prefItem1.getValue(values.getKey()));
+ }
+
+ final List<PrefItem> prefItems1 = TestUtils.convertToList(prefItem1.getChildren());
+ final List<PrefItem> prefItems2 = TestUtils.convertToList(prefItem2.getChildren());
+ Assert.assertEquals(prefItems1.size(), prefItems2.size());
+ for (int childIndex = 0; childIndex < prefItems1.size(); childIndex++) {
+ assertPrefItemsEqual(prefItems1.get(childIndex), prefItems2.get(childIndex));
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/test/java/com/anysoftkeyboard/ui/settings/BaseSettingsFragmentTest.java b/app/src/test/java/com/anysoftkeyboard/ui/settings/BaseSettingsFragmentTest.java
index 6876347f9..e773c5e61 100644
--- a/app/src/test/java/com/anysoftkeyboard/ui/settings/BaseSettingsFragmentTest.java
+++ b/app/src/test/java/com/anysoftkeyboard/ui/settings/BaseSettingsFragmentTest.java
@@ -1,9 +1,7 @@
package com.anysoftkeyboard.ui.settings;
import android.content.res.Configuration;
-import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
-import android.view.View;
import android.widget.LinearLayout;
import com.anysoftkeyboard.AnySoftKeyboardRobolectricTestRunner;
@@ -13,9 +11,7 @@ import com.menny.android.anysoftkeyboard.R;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
@RunWith(AnySoftKeyboardRobolectricTestRunner.class)
@@ -41,14 +37,4 @@ public abstract class BaseSettingsFragmentTest<T extends Fragment> extends Robol
Assert.assertEquals(LinearLayout.VERTICAL, rootView.getOrientation());
}
- @NonNull
- protected Fragment navigateByClicking(Fragment rootFragment, int viewToClick) {
- final View viewById = rootFragment.getView().findViewById(viewToClick);
- Assert.assertNotNull(viewById);
- final View.OnClickListener onClickListener = Shadows.shadowOf(viewById).getOnClickListener();
- Assert.assertNotNull(onClickListener);
- onClickListener.onClick(viewById);
- Robolectric.flushForegroundThreadScheduler();
- return rootFragment.getActivity().getSupportFragmentManager().findFragmentById(R.id.main_ui_content);
- }
} \ No newline at end of file
diff --git a/app/src/test/java/com/anysoftkeyboard/ui/settings/LanguageSettingsFragmentTest.java b/app/src/test/java/com/anysoftkeyboard/ui/settings/LanguageSettingsFragmentTest.java
index 35777f26c..9fc239f9b 100644
--- a/app/src/test/java/com/anysoftkeyboard/ui/settings/LanguageSettingsFragmentTest.java
+++ b/app/src/test/java/com/anysoftkeyboard/ui/settings/LanguageSettingsFragmentTest.java
@@ -3,6 +3,7 @@ package com.anysoftkeyboard.ui.settings;
import android.support.annotation.NonNull;
import com.anysoftkeyboard.AnySoftKeyboardRobolectricTestRunner;
+import com.anysoftkeyboard.ViewTestUtils;
import com.menny.android.anysoftkeyboard.R;
import org.junit.Assert;
@@ -22,20 +23,20 @@ public class LanguageSettingsFragmentTest extends BaseSettingsFragmentTest<Langu
public void testNavigationKeyboards() {
final LanguageSettingsFragment languageSettingsFragment = startFragment();
- Assert.assertTrue(navigateByClicking(languageSettingsFragment, R.id.settings_tile_keyboards) instanceof KeyboardAddOnBrowserFragment);
+ Assert.assertTrue(ViewTestUtils.navigateByClicking(languageSettingsFragment, R.id.settings_tile_keyboards) instanceof KeyboardAddOnBrowserFragment);
}
@Test
public void testNavigationGrammar() {
final LanguageSettingsFragment languageSettingsFragment = startFragment();
- Assert.assertTrue(navigateByClicking(languageSettingsFragment, R.id.settings_tile_grammar) instanceof DictionariesFragment);
+ Assert.assertTrue(ViewTestUtils.navigateByClicking(languageSettingsFragment, R.id.settings_tile_grammar) instanceof DictionariesFragment);
}
@Test
public void testNavigationTweaks() {
final LanguageSettingsFragment languageSettingsFragment = startFragment();
- Assert.assertTrue(navigateByClicking(languageSettingsFragment, R.id.settings_tile_even_more) instanceof AdditionalLanguageSettingsFragment);
+ Assert.assertTrue(ViewTestUtils.navigateByClicking(languageSettingsFragment, R.id.settings_tile_even_more) instanceof AdditionalLanguageSettingsFragment);
}
} \ No newline at end of file
diff --git a/app/src/test/java/com/anysoftkeyboard/ui/settings/MainFragmentTest.java b/app/src/test/java/com/anysoftkeyboard/ui/settings/MainFragmentTest.java
index c6a1b9b1b..62ab8d046 100644
--- a/app/src/test/java/com/anysoftkeyboard/ui/settings/MainFragmentTest.java
+++ b/app/src/test/java/com/anysoftkeyboard/ui/settings/MainFragmentTest.java
@@ -50,4 +50,23 @@ public class MainFragmentTest extends RobolectricFragmentTestCase<MainFragment>
Assert.assertNotNull(aboutFragment);
Assert.assertTrue(aboutFragment instanceof AboutAnySoftKeyboardFragment);
}
+
+ @Test
+ public void testTweaksMenuCommand() throws Exception {
+ final MainFragment fragment = startFragment();
+ final FragmentActivity activity = fragment.getActivity();
+
+ Menu menu = Shadows.shadowOf(activity).getOptionsMenu();
+ Assert.assertNotNull(menu);
+ final MenuItem item = menu.findItem(R.id.tweaks_menu_option);
+ Assert.assertNotNull(item);
+ Assert.assertTrue(item.isVisible());
+
+ fragment.onOptionsItemSelected(item);
+ Robolectric.flushForegroundThreadScheduler();
+
+ Fragment aboutFragment = activity.getSupportFragmentManager().findFragmentById(R.id.main_ui_content);
+ Assert.assertNotNull(aboutFragment);
+ Assert.assertTrue(aboutFragment instanceof MainTweaksFragment);
+ }
} \ No newline at end of file
diff --git a/app/src/test/java/com/anysoftkeyboard/ui/settings/MainTweaksFragmentTest.java b/app/src/test/java/com/anysoftkeyboard/ui/settings/MainTweaksFragmentTest.java
new file mode 100644
index 000000000..0fca900f0
--- /dev/null
+++ b/app/src/test/java/com/anysoftkeyboard/ui/settings/MainTweaksFragmentTest.java
@@ -0,0 +1,88 @@
+package com.anysoftkeyboard.ui.settings;
+
+import android.support.annotation.NonNull;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.preference.Preference;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.anysoftkeyboard.RobolectricFragmentTestCase;
+import com.anysoftkeyboard.prefs.GlobalPrefsBackup;
+import com.anysoftkeyboard.ui.GeneralDialogControllerTest;
+import com.anysoftkeyboard.ui.dev.DeveloperToolsFragment;
+import com.menny.android.anysoftkeyboard.R;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+
+public class MainTweaksFragmentTest extends RobolectricFragmentTestCase<MainTweaksFragment> {
+
+ @NonNull
+ @Override
+ protected MainTweaksFragment createFragment() {
+ return new MainTweaksFragment();
+ }
+
+ @Test
+ public void testNavigateToDevTools() {
+ MainTweaksFragment fragment = startFragment();
+
+ final Preference preferenceDevTools = fragment.findPreference(MainTweaksFragment.DEV_TOOLS_KEY);
+ preferenceDevTools.getOnPreferenceClickListener().onPreferenceClick(preferenceDevTools);
+
+ Robolectric.flushForegroundThreadScheduler();
+ Fragment navigatedToFragment = fragment.getActivity().getSupportFragmentManager().findFragmentById(R.id.main_ui_content);
+ Assert.assertTrue(navigatedToFragment instanceof DeveloperToolsFragment);
+ }
+
+ @Test
+ public void testBackupMenuItem() throws Exception {
+ final MainTweaksFragment fragment = startFragment();
+ final FragmentActivity activity = fragment.getActivity();
+
+ Menu menu = Shadows.shadowOf(activity).getOptionsMenu();
+ Assert.assertNotNull(menu);
+ final MenuItem item = menu.findItem(R.id.backup_prefs);
+ Assert.assertNotNull(item);
+
+ fragment.onOptionsItemSelected(item);
+
+ final AlertDialog dialog = GeneralDialogControllerTest.getLatestShownDialog();
+ Assert.assertNotNull(dialog);
+ Assert.assertEquals(RuntimeEnvironment.application.getText(R.string.word_editor_action_backup_words), GeneralDialogControllerTest.getTitleFromDialog(dialog));
+ Assert.assertNotNull(dialog.getListView());
+ Assert.assertEquals(GlobalPrefsBackup.getAllPrefsProviders(RuntimeEnvironment.application).size(), dialog.getListView().getCount());
+/*
+ Assert.assertTrue(AnyApplication.getBackupFile(MainTweaksFragment.GLOBAL_BACKUP_FILENAME).exists());
+ Assert.assertTrue(AnyApplication.getBackupFile(MainTweaksFragment.GLOBAL_BACKUP_FILENAME).length() > 0);
+*/
+ }
+
+ @Test
+ public void testRestoreMenuItem() throws Exception {
+ final MainTweaksFragment fragment = startFragment();
+ final FragmentActivity activity = fragment.getActivity();
+
+ Menu menu = Shadows.shadowOf(activity).getOptionsMenu();
+ Assert.assertNotNull(menu);
+ final MenuItem item = menu.findItem(R.id.restore_prefs);
+ Assert.assertNotNull(item);
+
+ fragment.onOptionsItemSelected(item);
+
+ final AlertDialog dialog = GeneralDialogControllerTest.getLatestShownDialog();
+ Assert.assertNotNull(dialog);
+ Assert.assertEquals(RuntimeEnvironment.application.getText(R.string.word_editor_action_restore_words), GeneralDialogControllerTest.getTitleFromDialog(dialog));
+ Assert.assertNotNull(dialog.getListView());
+ Assert.assertEquals(GlobalPrefsBackup.getAllPrefsProviders(RuntimeEnvironment.application).size(), dialog.getListView().getCount());
+/*
+ Assert.assertTrue(AnyApplication.getBackupFile(MainTweaksFragment.GLOBAL_BACKUP_FILENAME).exists());
+ Assert.assertTrue(AnyApplication.getBackupFile(MainTweaksFragment.GLOBAL_BACKUP_FILENAME).length() > 0);
+*/
+ }
+} \ No newline at end of file
diff --git a/app/src/test/java/com/anysoftkeyboard/ui/settings/UserInterfaceSettingsFragmentTest.java b/app/src/test/java/com/anysoftkeyboard/ui/settings/UserInterfaceSettingsFragmentTest.java
index 517506b7e..002170009 100644
--- a/app/src/test/java/com/anysoftkeyboard/ui/settings/UserInterfaceSettingsFragmentTest.java
+++ b/app/src/test/java/com/anysoftkeyboard/ui/settings/UserInterfaceSettingsFragmentTest.java
@@ -5,6 +5,7 @@ import android.support.v4.app.Fragment;
import android.view.View;
import com.anysoftkeyboard.AnySoftKeyboardRobolectricTestRunner;
+import com.anysoftkeyboard.ViewTestUtils;
import com.menny.android.anysoftkeyboard.R;
import org.junit.Assert;
@@ -40,20 +41,20 @@ public class UserInterfaceSettingsFragmentTest extends BaseSettingsFragmentTest<
public void testNavigationThemes() {
final Fragment fragment = startFragment();
- Assert.assertTrue(navigateByClicking(fragment, R.id.settings_tile_themes) instanceof KeyboardThemeSelectorFragment);
+ Assert.assertTrue(ViewTestUtils.navigateByClicking(fragment, R.id.settings_tile_themes) instanceof KeyboardThemeSelectorFragment);
}
@Test
public void testNavigationEffects() {
final Fragment fragment = startFragment();
- Assert.assertTrue(navigateByClicking(fragment, R.id.settings_tile_effects) instanceof EffectsSettingsFragment);
+ Assert.assertTrue(ViewTestUtils.navigateByClicking(fragment, R.id.settings_tile_effects) instanceof EffectsSettingsFragment);
}
@Test
public void testNavigationTweaks() {
final Fragment fragment = startFragment();
- Assert.assertTrue(navigateByClicking(fragment, R.id.settings_tile_even_more) instanceof AdditionalUiSettingsFragment);
+ Assert.assertTrue(ViewTestUtils.navigateByClicking(fragment, R.id.settings_tile_even_more) instanceof AdditionalUiSettingsFragment);
}
} \ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 6765b70d6..ea7918cac 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,7 +11,7 @@ buildscript {
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.1.0-alpha09'
+ classpath 'com.android.tools.build:gradle:3.1.0-beta1'
classpath 'com.github.Triple-T:gradle-play-publisher:8cda31a5d0e3c4f2d7f47ffde6fc3b370e59dd8a'
classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13"
}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 70489cefb..eaa7667fd 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index aa783d434..be280bec0 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Fri Jan 26 20:53:35 EST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-rc-2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-bin.zip
diff --git a/prefs/src/main/java/com/anysoftkeyboard/prefs/RxSharedPrefs.java b/prefs/src/main/java/com/anysoftkeyboard/prefs/RxSharedPrefs.java
index 68dee9bde..fbd4f86ca 100644
--- a/prefs/src/main/java/com/anysoftkeyboard/prefs/RxSharedPrefs.java
+++ b/prefs/src/main/java/com/anysoftkeyboard/prefs/RxSharedPrefs.java
@@ -28,7 +28,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.annotation.StringRes;
-import android.support.annotation.VisibleForTesting;
import android.support.v4.content.SharedPreferencesCompat;
import com.anysoftkeyboard.base.utils.Logger;
@@ -154,8 +153,7 @@ public class RxSharedPrefs {
T parse(String value);
}
- @VisibleForTesting
- static class SharedPrefsProvider implements PrefsProvider {
+ public static class SharedPrefsProvider implements PrefsProvider {
private final SharedPreferences mSharedPreferences;
diff --git a/prefs/src/main/java/com/anysoftkeyboard/prefs/backup/PrefItem.java b/prefs/src/main/java/com/anysoftkeyboard/prefs/backup/PrefItem.java
index 26148bfda..85d6b0476 100644
--- a/prefs/src/main/java/com/anysoftkeyboard/prefs/backup/PrefItem.java
+++ b/prefs/src/main/java/com/anysoftkeyboard/prefs/backup/PrefItem.java
@@ -47,4 +47,8 @@ public class PrefItem {
throw new IllegalArgumentException("The key '" + text + "' has non ASCII or has whitespaces or is empty! This is not valid as an XML attribute");
}
}
+
+ public void addChild(PrefItem prefsItem) {
+ mChildren.add(prefsItem);
+ }
}