Clipboard suggestions (#647)

This commit is contained in:
codokie 2024-07-06 00:14:54 +03:00 committed by GitHub
parent 21124a5a45
commit bdab98c2c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 213 additions and 18 deletions

View file

@ -3,6 +3,7 @@
package helium314.keyboard.compat;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipboardManager;
import android.os.Build;
@ -29,4 +30,11 @@ public class ClipboardManagerCompat {
}
}
public static Boolean getClipSensitivity(final ClipDescription cd) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return cd != null && cd.getExtras() != null && cd.getExtras().getBoolean("android.content.extra.IS_SENSITIVE");
}
return null; // can't determine
}
}

View file

@ -4,12 +4,24 @@ package helium314.keyboard.latin
import android.content.ClipboardManager
import android.content.Context
import android.text.InputType
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.view.isGone
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import helium314.keyboard.compat.ClipboardManagerCompat
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
import helium314.keyboard.latin.common.ColorType
import helium314.keyboard.latin.common.isValidNumber
import helium314.keyboard.latin.databinding.ClipboardSuggestionBinding
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.DeviceProtectedUtils
import helium314.keyboard.latin.utils.InputTypeUtils
import helium314.keyboard.latin.utils.ToolbarKey
import kotlin.collections.ArrayList
class ClipboardHistoryManager(
@ -18,6 +30,7 @@ class ClipboardHistoryManager(
private lateinit var clipboardManager: ClipboardManager
private var onHistoryChangeListener: OnHistoryChangeListener? = null
private var clipboardSuggestionView: View? = null
fun onCreate() {
clipboardManager = latinIME.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
@ -36,6 +49,7 @@ class ClipboardHistoryManager(
// Make sure we read clipboard content only if history settings is set
if (latinIME.mSettings.current?.mClipboardHistoryEnabled == true) {
fetchPrimaryClip()
dontShowCurrentSuggestion = false
}
}
@ -90,6 +104,7 @@ class ClipboardHistoryManager(
if (onHistoryChangeListener != null) {
onHistoryChangeListener?.onClipboardHistoryEntriesRemoved(pos, count)
}
removeClipboardSuggestion()
}
fun canRemove(index: Int) = historyEntries.getOrNull(index)?.isPinned != true
@ -131,6 +146,11 @@ class ClipboardHistoryManager(
return clipData.getItemAt(0)?.coerceToText(latinIME) ?: ""
}
private fun isClipSensitive(inputType: Int): Boolean {
ClipboardManagerCompat.getClipSensitivity(clipboardManager.primaryClip?.description)?.let { return it }
return InputTypeUtils.isPasswordInputType(inputType)
}
// pinned clips are stored in default shared preferences, not in device protected preferences!
private fun loadPinnedClips() {
val pinnedClipString = Settings.readPinnedClipString(latinIME)
@ -156,8 +176,66 @@ class ClipboardHistoryManager(
fun onClipboardHistoryEntryMoved(from: Int, to: Int)
}
fun getClipboardSuggestionView(editorInfo: EditorInfo?, parent: ViewGroup?): View? {
// maybe no need to create a new view
// but a cache has to consider a few possible changes, so better don't implement without need
clipboardSuggestionView = null
// get the content, or return null
if (!latinIME.mSettings.current.mSuggestClipboardContent) return null
if (dontShowCurrentSuggestion) return null
if (parent == null) return null
val clipData = clipboardManager.primaryClip ?: return null
if (clipData.itemCount == 0 || clipData.description?.hasMimeType("text/*") == false) return null
val clipItem = clipData.getItemAt(0) ?: return null
val timeStamp = ClipboardManagerCompat.getClipTimestamp(clipData) ?: System.currentTimeMillis()
if (System.currentTimeMillis() - timeStamp > RECENT_TIME_MILLIS) return null
val content = clipItem.coerceToText(latinIME)
if (TextUtils.isEmpty(content)) return null
val inputType = editorInfo?.inputType ?: InputType.TYPE_NULL
if (InputTypeUtils.isNumberInputType(inputType) && !content.isValidNumber()) return null
// create the view
val binding = ClipboardSuggestionBinding.inflate(LayoutInflater.from(latinIME), parent, false)
val textView = binding.clipboardSuggestionText
textView.text = if (isClipSensitive(inputType)) "*".repeat(content.length) else content
val clipIcon = latinIME.mKeyboardSwitcher.keyboard.mIconsSet.getIconDrawable(ToolbarKey.CLIPBOARD.name.lowercase())
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(clipIcon, null, null, null)
textView.setOnClickListener {
dontShowCurrentSuggestion = true
latinIME.onTextInput(content.toString())
AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(KeyCode.NOT_SPECIFIED, it);
binding.root.isGone = true
}
val closeButton = binding.clipboardSuggestionClose
closeButton.setImageDrawable(latinIME.mKeyboardSwitcher.keyboard.mIconsSet.getIconDrawable(ToolbarKey.CLOSE_HISTORY.name.lowercase()))
closeButton.setOnClickListener { removeClipboardSuggestion() }
val colors = latinIME.mSettings.current.mColors
textView.setTextColor(colors.get(ColorType.KEY_TEXT))
clipIcon?.let { colors.setColor(it, ColorType.KEY_ICON) }
colors.setColor(closeButton, ColorType.REMOVE_SUGGESTION_ICON)
colors.setBackground(binding.root, ColorType.CLIPBOARD_SUGGESTION_BACKGROUND)
clipboardSuggestionView = binding.root
return clipboardSuggestionView
}
private fun removeClipboardSuggestion() {
dontShowCurrentSuggestion = true
val csv = clipboardSuggestionView ?: return
if (csv.parent != null && !csv.isGone) {
// clipboard view is shown ->
latinIME.setNeutralSuggestionStrip()
latinIME.mHandler.postResumeSuggestions(false)
}
csv.isGone = true
}
companion object {
// store pinned clips in companion object so they survive a keyboard switch (which destroys the current instance)
private val historyEntries: MutableList<ClipboardHistoryEntry> = ArrayList()
private var dontShowCurrentSuggestion: Boolean = false
const val RECENT_TIME_MILLIS = 3 * 60 * 1000L // 3 minutes (for clipboard suggestions)
}
}

View file

@ -1029,12 +1029,11 @@ public class LatinIME extends InputMethodService implements
// Space state must be updated before calling updateShiftState
switcher.requestUpdatingShiftState(getCurrentAutoCapsState(), getCurrentRecapitalizeState());
}
// This will set the punctuation suggestions if next word suggestion is off;
// otherwise it will clear the suggestion strip.
// Set neutral suggestions and show the toolbar if the "Auto show toolbar" setting is enabled.
if (!mHandler.hasPendingResumeSuggestions()) {
mHandler.cancelUpdateSuggestionStrip();
setNeutralSuggestionStrip();
if (hasSuggestionStripView() && currentSettingsValues.mAutoShowToolbar) {
if (hasSuggestionStripView() && currentSettingsValues.mAutoShowToolbar && !tryShowClipboardSuggestion()) {
mSuggestionStripView.setToolbarVisibility(true);
}
}
@ -1330,7 +1329,7 @@ public class LatinIME extends InputMethodService implements
// Without this function the inline autofill suggestions will not be visible
mHandler.cancelResumeSuggestions();
mSuggestionStripView.setInlineSuggestionsView(inlineSuggestionView);
mSuggestionStripView.setExternalSuggestionView(inlineSuggestionView);
return true;
}
@ -1652,13 +1651,33 @@ public class LatinIME extends InputMethodService implements
updateStateAfterInputTransaction(completeInputTransaction);
}
// This will show either an empty suggestion strip (if prediction is enabled) or
// punctuation suggestions (if it's disabled).
// The toolbar will be shown automatically if the relevant setting is enabled
/**
* Checks if a recent clipboard suggestion is available. If available, it is set in suggestion strip.
* returns whether a clipboard suggestion has been set.
*/
public boolean tryShowClipboardSuggestion() {
final View clipboardView = mClipboardHistoryManager.getClipboardSuggestionView(getCurrentInputEditorInfo(), mSuggestionStripView);
if (clipboardView != null && hasSuggestionStripView()) {
mSuggestionStripView.setExternalSuggestionView(clipboardView);
return true;
}
return false;
}
// This will first try showing a clipboard suggestion. On success, the toolbar will be hidden
// if the "Auto hide toolbar" is enabled. Otherwise, an empty suggestion strip (if prediction
// is enabled) or punctuation suggestions (if it's disabled) will be set.
// Then, the toolbar will be shown automatically if the relevant setting is enabled
// and there is a selection of text or it's the start of a line.
@Override
public void setNeutralSuggestionStrip() {
final SettingsValues currentSettings = mSettings.getCurrent();
if (tryShowClipboardSuggestion()) {
// clipboard suggestion has been set
if (hasSuggestionStripView() && currentSettings.mAutoHideToolbar)
mSuggestionStripView.setToolbarVisibility(false);
return;
}
final SuggestedWords neutralSuggestions = currentSettings.mBigramPredictionEnabled
? SuggestedWords.getEmptyInstance()
: currentSettings.mSpacingAndPunctuations.mSuggestPuncList;

View file

@ -286,6 +286,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override
KEY_BACKGROUND -> keyBackground
ACTION_KEY_POPUP_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackground else accent
STRIP_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackground else background
CLIPBOARD_SUGGESTION_BACKGROUND -> doubleAdjustedBackground
NAVIGATION_BAR -> navBar
MORE_SUGGESTIONS_HINT, SUGGESTED_WORD, SUGGESTION_TYPED_WORD, SUGGESTION_VALID_WORD -> adjustedKeyText
ACTION_KEY_ICON, TOOL_BAR_EXPAND_KEY -> Color.WHITE
@ -467,7 +468,7 @@ class DefaultColors (
CLIPBOARD_PIN, SHIFT_KEY_ICON -> accent
AUTOFILL_BACKGROUND_CHIP -> if (themeStyle == STYLE_MATERIAL && !hasKeyBorders) background else adjustedBackground
GESTURE_PREVIEW, POPUP_KEYS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND, KEY_PREVIEW -> adjustedBackground
TOOL_BAR_EXPAND_KEY_BACKGROUND -> doubleAdjustedBackground
TOOL_BAR_EXPAND_KEY_BACKGROUND, CLIPBOARD_SUGGESTION_BACKGROUND -> doubleAdjustedBackground
GESTURE_TRAIL -> gesture
KEY_TEXT, REMOVE_SUGGESTION_ICON, FUNCTIONAL_KEY_TEXT, KEY_ICON -> keyText
KEY_HINT_TEXT -> keyHintText
@ -519,7 +520,7 @@ class DefaultColors (
view.setBackgroundColor(Color.WHITE) // set white to make the color filters work
when (color) {
KEY_PREVIEW, POPUP_KEYS_BACKGROUND -> view.background.colorFilter = adjustedBackgroundFilter
FUNCTIONAL_KEY_BACKGROUND, KEY_BACKGROUND, MORE_SUGGESTIONS_WORD_BACKGROUND, SPACE_BAR_BACKGROUND, STRIP_BACKGROUND -> setColor(view.background, color)
FUNCTIONAL_KEY_BACKGROUND, KEY_BACKGROUND, MORE_SUGGESTIONS_WORD_BACKGROUND, SPACE_BAR_BACKGROUND, STRIP_BACKGROUND, CLIPBOARD_SUGGESTION_BACKGROUND -> setColor(view.background, color)
ONE_HANDED_MODE_BUTTON -> setColor(view.background, if (keyboardBackground == null) MAIN_BACKGROUND else STRIP_BACKGROUND)
MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter
MAIN_BACKGROUND -> {
@ -658,6 +659,7 @@ enum class ColorType {
ONE_HANDED_MODE_BUTTON,
REMOVE_SUGGESTION_ICON,
STRIP_BACKGROUND,
CLIPBOARD_SUGGESTION_BACKGROUND,
SUGGESTED_WORD,
SUGGESTION_AUTO_CORRECT,
SUGGESTION_TYPED_WORD,

View file

@ -103,6 +103,10 @@ fun String.splitOnFirstSpacesOnly(): List<String> {
return out
}
fun CharSequence.isValidNumber(): Boolean {
return this.toString().toDoubleOrNull() != null
}
fun String.decapitalize(locale: Locale): String {
if (isEmpty() || !this[0].isUpperCase())
return this

View file

@ -1648,7 +1648,11 @@ public final class InputLogic {
final SuggestedWords suggestedWords = holder.get(null,
Constants.GET_SUGGESTED_WORDS_TIMEOUT);
if (suggestedWords != null) {
mSuggestionStripViewAccessor.showSuggestionStrip(suggestedWords);
// Prefer clipboard suggestions (if available and setting is enabled) over beginning of sentence predictions.
if (!(suggestedWords.mInputStyle == SuggestedWords.INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION
&& mLatinIME.tryShowClipboardSuggestion())) {
mSuggestionStripViewAccessor.showSuggestionStrip(suggestedWords);
}
}
if (DebugFlags.DEBUG_ENABLED) {
long runTimeMillis = System.currentTimeMillis() - startTimeMillis;

View file

@ -107,6 +107,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_AUTOSPACE_AFTER_PUNCTUATION = "autospace_after_punctuation";
public static final String PREF_ALWAYS_INCOGNITO_MODE = "always_incognito_mode";
public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction";
public static final String PREF_SUGGEST_CLIPBOARD_CONTENT = "suggest_clipboard_content";
public static final String PREF_GESTURE_INPUT = "gesture_input";
public static final String PREF_VIBRATION_DURATION_SETTINGS = "vibration_duration_settings";
public static final String PREF_KEYPRESS_SOUND_VOLUME = "keypress_sound_volume";

View file

@ -125,6 +125,7 @@ public class SettingsValues {
public final int mScoreLimitForAutocorrect;
private final boolean mSuggestionsEnabledPerUserSettings;
private final boolean mOverrideShowingSuggestions;
public final boolean mSuggestClipboardContent;
public final SettingsValuesForSuggestion mSettingsValuesForSuggestion;
public final boolean mIncognitoModeEnabled;
public final boolean mLongPressSymbolsForNumpad;
@ -179,6 +180,7 @@ public class SettingsValues {
mScoreLimitForAutocorrect = (mAutoCorrectionThreshold < 0) ? 600000 // very aggressive
: (mAutoCorrectionThreshold < 0.07 ? 800000 : 950000); // aggressive or modest
mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res);
mSuggestClipboardContent = readSuggestClipboardContent(prefs, res);
mDoubleSpacePeriodTimeout = res.getInteger(R.integer.config_double_space_period_timeout);
mHasHardwareKeyboard = Settings.readHasHardwareKeyboard(res.getConfiguration());
final float displayWidthDp = TypedValueCompat.pxToDp(res.getDisplayMetrics().widthPixels, res.getDisplayMetrics());
@ -327,6 +329,12 @@ public class SettingsValues {
R.bool.config_default_next_word_prediction));
}
private static boolean readSuggestClipboardContent (SharedPreferences prefs,
final Resources res) {
return prefs.getBoolean(Settings.PREF_SUGGEST_CLIPBOARD_CONTENT, res.getBoolean(
R.bool.config_default_suggest_clipboard_content));
}
private static float readAutoCorrectionThreshold(final Resources res,
final SharedPreferences prefs) {
final String currentAutoCorrectionSetting = Settings.readAutoCorrectConfidence(prefs, res);

View file

@ -26,7 +26,6 @@ import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
@ -59,7 +58,6 @@ import helium314.keyboard.latin.settings.Settings;
import helium314.keyboard.latin.settings.SettingsValues;
import helium314.keyboard.latin.suggestions.PopupSuggestionsView.MoreSuggestionsListener;
import helium314.keyboard.latin.utils.DeviceProtectedUtils;
import helium314.keyboard.latin.utils.DialogUtilsKt;
import helium314.keyboard.latin.utils.Log;
import helium314.keyboard.latin.utils.ToolbarKey;
import helium314.keyboard.latin.utils.ToolbarUtilsKt;
@ -69,7 +67,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.PopupMenu;
public final class SuggestionStripView extends RelativeLayout implements OnClickListener,
OnLongClickListener {
@ -110,7 +107,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
private final SuggestionStripLayoutHelper mLayoutHelper;
private final StripVisibilityGroup mStripVisibilityGroup;
private boolean isInlineAutofillSuggestionsVisible = false; // Required to disable the more suggestions if inline autofill suggestions are visible
private boolean isExternalSuggestionVisible = false; // Required to disable the more suggestions if other suggestions are visible
private static class StripVisibilityGroup {
private final View mSuggestionStripView;
@ -258,7 +255,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
: km.isKeyguardLocked();
mToolbarExpandKey.setOnClickListener(hideToolbarKeys ? null : this);
mPinnedKeys.setVisibility(hideToolbarKeys ? GONE : mSuggestionsStrip.getVisibility());
isInlineAutofillSuggestionsVisible = false;
isExternalSuggestionVisible = false;
}
public void setRtl(final boolean isRtlLanguage) {
@ -281,9 +278,9 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
getContext(), mSuggestedWords, mSuggestionsStrip, this);
}
public void setInlineSuggestionsView(final View view) {
public void setExternalSuggestionView(final View view) {
clear();
isInlineAutofillSuggestionsVisible = true;
isExternalSuggestionVisible = true;
mSuggestionsStrip.addView(view);
if (Settings.getInstance().getCurrent().mAutoHideToolbar)
setToolbarVisibility(false);
@ -548,7 +545,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
public boolean onInterceptTouchEvent(final MotionEvent me) {
// Disable More Suggestions if inline autofill suggestions is visible
if(isInlineAutofillSuggestionsVisible) {
if(isExternalSuggestionVisible) {
return false;
}

View file

@ -18,6 +18,8 @@ public final class InputTypeUtils implements InputType {
TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
private static final int TEXT_VISIBLE_PASSWORD_INPUT_TYPE =
TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
private static final int TEXT_NUMBER_INPUT_TYPE =
TYPE_CLASS_NUMBER | TYPE_NUMBER_FLAG_DECIMAL;
private static final int[] SUPPRESSING_AUTO_SPACES_FIELD_VARIATION = {
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS,
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
@ -46,6 +48,10 @@ public final class InputTypeUtils implements InputType {
return variation == TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
}
public static boolean isNumberInputType(final int inputType) {
return (inputType & TEXT_NUMBER_INPUT_TYPE) != 0;
}
public static boolean isEmailVariation(final int variation) {
return variation == TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|| isWebEmailAddressVariation(variation);

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020 The Android Open Source Project
SPDX-License-Identifier: Apache-2.0
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#14000000">
<item
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:shape="rectangle"
android:top="5dp">
<shape>
<corners android:radius="32dp"/>
<stroke android:color="#1F000000" android:width="1dp"/>
<solid android:color="#FFFFFFFF"/>
</shape>
</item>
</ripple>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:background="@drawable/clipboard_suggestion_background"
android:gravity="center"
android:paddingRight="12dp"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="@+id/clipboard_suggestion_text"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:contentDescription="@string/spoken_clipboard_suggestion"
android:drawablePadding="3dp"
android:paddingHorizontal="12dp"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false"
android:singleLine="true"
android:gravity="center"
android:ellipsize="end"
android:textStyle="bold"
style="?android:attr/textAppearanceSmall" />
<ImageView
android:id="@+id/clipboard_suggestion_close"
android:src="@drawable/ic_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center" />
</LinearLayout>

View file

@ -51,6 +51,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_horizontal"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false" />
<LinearLayout

View file

@ -96,6 +96,9 @@
<dimen name="config_more_suggestions_modal_tolerance">32.0dp</dimen>
<fraction name="config_more_suggestions_info_ratio">18%</fraction>
<!-- Common clipboard suggestion configuration. -->
<bool name="config_default_suggest_clipboard_content">true</bool>
<!-- Common gesture trail parameters -->
<!-- Minimum distance between gesture trail sampling points. -->
<dimen name="config_gesture_trail_min_sampling_distance">9.6dp</dimen>

View file

@ -20,6 +20,8 @@
<!-- Spoken description of a suggestion when nothing is specified and the field is blank. -->
<string name="spoken_empty_suggestion">No suggestion</string>
<!-- Spoken description of a suggestion when clipboard content appears as a suggestion. -->
<string name="spoken_clipboard_suggestion">Clipboard suggestion</string>
<!-- Spoken description for unknown keyboard keys. -->
<string name="spoken_description_unknown">Unknown character</string>

View file

@ -134,6 +134,10 @@
<string name="bigram_prediction">Next-word suggestions</string>
<!-- Description for "next word suggestion" option. This displays suggestions even when there is no input, based on the previous word. -->
<string name="bigram_prediction_summary">Use the previous word in making suggestions</string>
<!-- Option to enable the suggestion of clipboard content. -->
<string name="suggest_clipboard_content">Suggest clipboard content</string>
<!-- Description for the "suggest clipboard content" option. This makes the primary clipboard content visible in the suggestion strip view. -->
<string name="suggest_clipboard_content_summary">Show recently copied clipboard content as a suggestion</string>
<!-- Option to enable gesture input. The user can input a word by tracing the letters of a word without releasing the finger from the screen. [CHAR LIMIT=30]-->
<string name="gesture_input">Enable gesture typing</string>
<!-- Description for "gesture_input" option. The user can input a word by tracing the letters of a word without releasing the finger from the screen. [CHAR LIMIT=65]-->

View file

@ -108,6 +108,13 @@
android:defaultValue="@bool/config_center_suggestion_text_to_enter"
android:persistent="true" />
<SwitchPreference
android:key="suggest_clipboard_content"
android:title="@string/suggest_clipboard_content"
android:defaultValue="@bool/config_default_suggest_clipboard_content"
android:summary="@string/suggest_clipboard_content_summary"
android:persistent="true" />
<SwitchPreference
android:key="use_contacts"
android:title="@string/use_contacts_dict"