mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-05-17 15:32:48 +00:00
Clipboard suggestions (#647)
This commit is contained in:
parent
21124a5a45
commit
bdab98c2c9
17 changed files with 213 additions and 18 deletions
|
@ -3,6 +3,7 @@
|
||||||
package helium314.keyboard.compat;
|
package helium314.keyboard.compat;
|
||||||
|
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipDescription;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.os.Build;
|
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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,24 @@ package helium314.keyboard.latin
|
||||||
|
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.text.InputType
|
||||||
import android.text.TextUtils
|
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.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import helium314.keyboard.compat.ClipboardManagerCompat
|
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.settings.Settings
|
||||||
import helium314.keyboard.latin.utils.DeviceProtectedUtils
|
import helium314.keyboard.latin.utils.DeviceProtectedUtils
|
||||||
|
import helium314.keyboard.latin.utils.InputTypeUtils
|
||||||
|
import helium314.keyboard.latin.utils.ToolbarKey
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class ClipboardHistoryManager(
|
class ClipboardHistoryManager(
|
||||||
|
@ -18,6 +30,7 @@ class ClipboardHistoryManager(
|
||||||
|
|
||||||
private lateinit var clipboardManager: ClipboardManager
|
private lateinit var clipboardManager: ClipboardManager
|
||||||
private var onHistoryChangeListener: OnHistoryChangeListener? = null
|
private var onHistoryChangeListener: OnHistoryChangeListener? = null
|
||||||
|
private var clipboardSuggestionView: View? = null
|
||||||
|
|
||||||
fun onCreate() {
|
fun onCreate() {
|
||||||
clipboardManager = latinIME.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
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
|
// Make sure we read clipboard content only if history settings is set
|
||||||
if (latinIME.mSettings.current?.mClipboardHistoryEnabled == true) {
|
if (latinIME.mSettings.current?.mClipboardHistoryEnabled == true) {
|
||||||
fetchPrimaryClip()
|
fetchPrimaryClip()
|
||||||
|
dontShowCurrentSuggestion = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +104,7 @@ class ClipboardHistoryManager(
|
||||||
if (onHistoryChangeListener != null) {
|
if (onHistoryChangeListener != null) {
|
||||||
onHistoryChangeListener?.onClipboardHistoryEntriesRemoved(pos, count)
|
onHistoryChangeListener?.onClipboardHistoryEntriesRemoved(pos, count)
|
||||||
}
|
}
|
||||||
|
removeClipboardSuggestion()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun canRemove(index: Int) = historyEntries.getOrNull(index)?.isPinned != true
|
fun canRemove(index: Int) = historyEntries.getOrNull(index)?.isPinned != true
|
||||||
|
@ -131,6 +146,11 @@ class ClipboardHistoryManager(
|
||||||
return clipData.getItemAt(0)?.coerceToText(latinIME) ?: ""
|
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!
|
// pinned clips are stored in default shared preferences, not in device protected preferences!
|
||||||
private fun loadPinnedClips() {
|
private fun loadPinnedClips() {
|
||||||
val pinnedClipString = Settings.readPinnedClipString(latinIME)
|
val pinnedClipString = Settings.readPinnedClipString(latinIME)
|
||||||
|
@ -156,8 +176,66 @@ class ClipboardHistoryManager(
|
||||||
fun onClipboardHistoryEntryMoved(from: Int, to: Int)
|
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 {
|
companion object {
|
||||||
// store pinned clips in companion object so they survive a keyboard switch (which destroys the current instance)
|
// store pinned clips in companion object so they survive a keyboard switch (which destroys the current instance)
|
||||||
private val historyEntries: MutableList<ClipboardHistoryEntry> = ArrayList()
|
private val historyEntries: MutableList<ClipboardHistoryEntry> = ArrayList()
|
||||||
|
private var dontShowCurrentSuggestion: Boolean = false
|
||||||
|
const val RECENT_TIME_MILLIS = 3 * 60 * 1000L // 3 minutes (for clipboard suggestions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1029,12 +1029,11 @@ public class LatinIME extends InputMethodService implements
|
||||||
// Space state must be updated before calling updateShiftState
|
// Space state must be updated before calling updateShiftState
|
||||||
switcher.requestUpdatingShiftState(getCurrentAutoCapsState(), getCurrentRecapitalizeState());
|
switcher.requestUpdatingShiftState(getCurrentAutoCapsState(), getCurrentRecapitalizeState());
|
||||||
}
|
}
|
||||||
// This will set the punctuation suggestions if next word suggestion is off;
|
// Set neutral suggestions and show the toolbar if the "Auto show toolbar" setting is enabled.
|
||||||
// otherwise it will clear the suggestion strip.
|
|
||||||
if (!mHandler.hasPendingResumeSuggestions()) {
|
if (!mHandler.hasPendingResumeSuggestions()) {
|
||||||
mHandler.cancelUpdateSuggestionStrip();
|
mHandler.cancelUpdateSuggestionStrip();
|
||||||
setNeutralSuggestionStrip();
|
setNeutralSuggestionStrip();
|
||||||
if (hasSuggestionStripView() && currentSettingsValues.mAutoShowToolbar) {
|
if (hasSuggestionStripView() && currentSettingsValues.mAutoShowToolbar && !tryShowClipboardSuggestion()) {
|
||||||
mSuggestionStripView.setToolbarVisibility(true);
|
mSuggestionStripView.setToolbarVisibility(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1330,7 +1329,7 @@ public class LatinIME extends InputMethodService implements
|
||||||
// Without this function the inline autofill suggestions will not be visible
|
// Without this function the inline autofill suggestions will not be visible
|
||||||
mHandler.cancelResumeSuggestions();
|
mHandler.cancelResumeSuggestions();
|
||||||
|
|
||||||
mSuggestionStripView.setInlineSuggestionsView(inlineSuggestionView);
|
mSuggestionStripView.setExternalSuggestionView(inlineSuggestionView);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1652,13 +1651,33 @@ public class LatinIME extends InputMethodService implements
|
||||||
updateStateAfterInputTransaction(completeInputTransaction);
|
updateStateAfterInputTransaction(completeInputTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will show either an empty suggestion strip (if prediction is enabled) or
|
/**
|
||||||
// punctuation suggestions (if it's disabled).
|
* Checks if a recent clipboard suggestion is available. If available, it is set in suggestion strip.
|
||||||
// The toolbar will be shown automatically if the relevant setting is enabled
|
* 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.
|
// and there is a selection of text or it's the start of a line.
|
||||||
@Override
|
@Override
|
||||||
public void setNeutralSuggestionStrip() {
|
public void setNeutralSuggestionStrip() {
|
||||||
final SettingsValues currentSettings = mSettings.getCurrent();
|
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
|
final SuggestedWords neutralSuggestions = currentSettings.mBigramPredictionEnabled
|
||||||
? SuggestedWords.getEmptyInstance()
|
? SuggestedWords.getEmptyInstance()
|
||||||
: currentSettings.mSpacingAndPunctuations.mSuggestPuncList;
|
: currentSettings.mSpacingAndPunctuations.mSuggestPuncList;
|
||||||
|
|
|
@ -286,6 +286,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override
|
||||||
KEY_BACKGROUND -> keyBackground
|
KEY_BACKGROUND -> keyBackground
|
||||||
ACTION_KEY_POPUP_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackground else accent
|
ACTION_KEY_POPUP_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackground else accent
|
||||||
STRIP_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackground else background
|
STRIP_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackground else background
|
||||||
|
CLIPBOARD_SUGGESTION_BACKGROUND -> doubleAdjustedBackground
|
||||||
NAVIGATION_BAR -> navBar
|
NAVIGATION_BAR -> navBar
|
||||||
MORE_SUGGESTIONS_HINT, SUGGESTED_WORD, SUGGESTION_TYPED_WORD, SUGGESTION_VALID_WORD -> adjustedKeyText
|
MORE_SUGGESTIONS_HINT, SUGGESTED_WORD, SUGGESTION_TYPED_WORD, SUGGESTION_VALID_WORD -> adjustedKeyText
|
||||||
ACTION_KEY_ICON, TOOL_BAR_EXPAND_KEY -> Color.WHITE
|
ACTION_KEY_ICON, TOOL_BAR_EXPAND_KEY -> Color.WHITE
|
||||||
|
@ -467,7 +468,7 @@ class DefaultColors (
|
||||||
CLIPBOARD_PIN, SHIFT_KEY_ICON -> accent
|
CLIPBOARD_PIN, SHIFT_KEY_ICON -> accent
|
||||||
AUTOFILL_BACKGROUND_CHIP -> if (themeStyle == STYLE_MATERIAL && !hasKeyBorders) background else adjustedBackground
|
AUTOFILL_BACKGROUND_CHIP -> if (themeStyle == STYLE_MATERIAL && !hasKeyBorders) background else adjustedBackground
|
||||||
GESTURE_PREVIEW, POPUP_KEYS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND, KEY_PREVIEW -> 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
|
GESTURE_TRAIL -> gesture
|
||||||
KEY_TEXT, REMOVE_SUGGESTION_ICON, FUNCTIONAL_KEY_TEXT, KEY_ICON -> keyText
|
KEY_TEXT, REMOVE_SUGGESTION_ICON, FUNCTIONAL_KEY_TEXT, KEY_ICON -> keyText
|
||||||
KEY_HINT_TEXT -> keyHintText
|
KEY_HINT_TEXT -> keyHintText
|
||||||
|
@ -519,7 +520,7 @@ class DefaultColors (
|
||||||
view.setBackgroundColor(Color.WHITE) // set white to make the color filters work
|
view.setBackgroundColor(Color.WHITE) // set white to make the color filters work
|
||||||
when (color) {
|
when (color) {
|
||||||
KEY_PREVIEW, POPUP_KEYS_BACKGROUND -> view.background.colorFilter = adjustedBackgroundFilter
|
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)
|
ONE_HANDED_MODE_BUTTON -> setColor(view.background, if (keyboardBackground == null) MAIN_BACKGROUND else STRIP_BACKGROUND)
|
||||||
MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter
|
MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter
|
||||||
MAIN_BACKGROUND -> {
|
MAIN_BACKGROUND -> {
|
||||||
|
@ -658,6 +659,7 @@ enum class ColorType {
|
||||||
ONE_HANDED_MODE_BUTTON,
|
ONE_HANDED_MODE_BUTTON,
|
||||||
REMOVE_SUGGESTION_ICON,
|
REMOVE_SUGGESTION_ICON,
|
||||||
STRIP_BACKGROUND,
|
STRIP_BACKGROUND,
|
||||||
|
CLIPBOARD_SUGGESTION_BACKGROUND,
|
||||||
SUGGESTED_WORD,
|
SUGGESTED_WORD,
|
||||||
SUGGESTION_AUTO_CORRECT,
|
SUGGESTION_AUTO_CORRECT,
|
||||||
SUGGESTION_TYPED_WORD,
|
SUGGESTION_TYPED_WORD,
|
||||||
|
|
|
@ -103,6 +103,10 @@ fun String.splitOnFirstSpacesOnly(): List<String> {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun CharSequence.isValidNumber(): Boolean {
|
||||||
|
return this.toString().toDoubleOrNull() != null
|
||||||
|
}
|
||||||
|
|
||||||
fun String.decapitalize(locale: Locale): String {
|
fun String.decapitalize(locale: Locale): String {
|
||||||
if (isEmpty() || !this[0].isUpperCase())
|
if (isEmpty() || !this[0].isUpperCase())
|
||||||
return this
|
return this
|
||||||
|
|
|
@ -1648,7 +1648,11 @@ public final class InputLogic {
|
||||||
final SuggestedWords suggestedWords = holder.get(null,
|
final SuggestedWords suggestedWords = holder.get(null,
|
||||||
Constants.GET_SUGGESTED_WORDS_TIMEOUT);
|
Constants.GET_SUGGESTED_WORDS_TIMEOUT);
|
||||||
if (suggestedWords != null) {
|
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) {
|
if (DebugFlags.DEBUG_ENABLED) {
|
||||||
long runTimeMillis = System.currentTimeMillis() - startTimeMillis;
|
long runTimeMillis = System.currentTimeMillis() - startTimeMillis;
|
||||||
|
|
|
@ -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_AUTOSPACE_AFTER_PUNCTUATION = "autospace_after_punctuation";
|
||||||
public static final String PREF_ALWAYS_INCOGNITO_MODE = "always_incognito_mode";
|
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_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_GESTURE_INPUT = "gesture_input";
|
||||||
public static final String PREF_VIBRATION_DURATION_SETTINGS = "vibration_duration_settings";
|
public static final String PREF_VIBRATION_DURATION_SETTINGS = "vibration_duration_settings";
|
||||||
public static final String PREF_KEYPRESS_SOUND_VOLUME = "keypress_sound_volume";
|
public static final String PREF_KEYPRESS_SOUND_VOLUME = "keypress_sound_volume";
|
||||||
|
|
|
@ -125,6 +125,7 @@ public class SettingsValues {
|
||||||
public final int mScoreLimitForAutocorrect;
|
public final int mScoreLimitForAutocorrect;
|
||||||
private final boolean mSuggestionsEnabledPerUserSettings;
|
private final boolean mSuggestionsEnabledPerUserSettings;
|
||||||
private final boolean mOverrideShowingSuggestions;
|
private final boolean mOverrideShowingSuggestions;
|
||||||
|
public final boolean mSuggestClipboardContent;
|
||||||
public final SettingsValuesForSuggestion mSettingsValuesForSuggestion;
|
public final SettingsValuesForSuggestion mSettingsValuesForSuggestion;
|
||||||
public final boolean mIncognitoModeEnabled;
|
public final boolean mIncognitoModeEnabled;
|
||||||
public final boolean mLongPressSymbolsForNumpad;
|
public final boolean mLongPressSymbolsForNumpad;
|
||||||
|
@ -179,6 +180,7 @@ public class SettingsValues {
|
||||||
mScoreLimitForAutocorrect = (mAutoCorrectionThreshold < 0) ? 600000 // very aggressive
|
mScoreLimitForAutocorrect = (mAutoCorrectionThreshold < 0) ? 600000 // very aggressive
|
||||||
: (mAutoCorrectionThreshold < 0.07 ? 800000 : 950000); // aggressive or modest
|
: (mAutoCorrectionThreshold < 0.07 ? 800000 : 950000); // aggressive or modest
|
||||||
mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res);
|
mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res);
|
||||||
|
mSuggestClipboardContent = readSuggestClipboardContent(prefs, res);
|
||||||
mDoubleSpacePeriodTimeout = res.getInteger(R.integer.config_double_space_period_timeout);
|
mDoubleSpacePeriodTimeout = res.getInteger(R.integer.config_double_space_period_timeout);
|
||||||
mHasHardwareKeyboard = Settings.readHasHardwareKeyboard(res.getConfiguration());
|
mHasHardwareKeyboard = Settings.readHasHardwareKeyboard(res.getConfiguration());
|
||||||
final float displayWidthDp = TypedValueCompat.pxToDp(res.getDisplayMetrics().widthPixels, res.getDisplayMetrics());
|
final float displayWidthDp = TypedValueCompat.pxToDp(res.getDisplayMetrics().widthPixels, res.getDisplayMetrics());
|
||||||
|
@ -327,6 +329,12 @@ public class SettingsValues {
|
||||||
R.bool.config_default_next_word_prediction));
|
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,
|
private static float readAutoCorrectionThreshold(final Resources res,
|
||||||
final SharedPreferences prefs) {
|
final SharedPreferences prefs) {
|
||||||
final String currentAutoCorrectionSetting = Settings.readAutoCorrectConfidence(prefs, res);
|
final String currentAutoCorrectionSetting = Settings.readAutoCorrectConfidence(prefs, res);
|
||||||
|
|
|
@ -26,7 +26,6 @@ import android.util.AttributeSet;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
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.settings.SettingsValues;
|
||||||
import helium314.keyboard.latin.suggestions.PopupSuggestionsView.MoreSuggestionsListener;
|
import helium314.keyboard.latin.suggestions.PopupSuggestionsView.MoreSuggestionsListener;
|
||||||
import helium314.keyboard.latin.utils.DeviceProtectedUtils;
|
import helium314.keyboard.latin.utils.DeviceProtectedUtils;
|
||||||
import helium314.keyboard.latin.utils.DialogUtilsKt;
|
|
||||||
import helium314.keyboard.latin.utils.Log;
|
import helium314.keyboard.latin.utils.Log;
|
||||||
import helium314.keyboard.latin.utils.ToolbarKey;
|
import helium314.keyboard.latin.utils.ToolbarKey;
|
||||||
import helium314.keyboard.latin.utils.ToolbarUtilsKt;
|
import helium314.keyboard.latin.utils.ToolbarUtilsKt;
|
||||||
|
@ -69,7 +67,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.widget.PopupMenu;
|
|
||||||
|
|
||||||
public final class SuggestionStripView extends RelativeLayout implements OnClickListener,
|
public final class SuggestionStripView extends RelativeLayout implements OnClickListener,
|
||||||
OnLongClickListener {
|
OnLongClickListener {
|
||||||
|
@ -110,7 +107,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
|
||||||
|
|
||||||
private final SuggestionStripLayoutHelper mLayoutHelper;
|
private final SuggestionStripLayoutHelper mLayoutHelper;
|
||||||
private final StripVisibilityGroup mStripVisibilityGroup;
|
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 static class StripVisibilityGroup {
|
||||||
private final View mSuggestionStripView;
|
private final View mSuggestionStripView;
|
||||||
|
@ -258,7 +255,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
|
||||||
: km.isKeyguardLocked();
|
: km.isKeyguardLocked();
|
||||||
mToolbarExpandKey.setOnClickListener(hideToolbarKeys ? null : this);
|
mToolbarExpandKey.setOnClickListener(hideToolbarKeys ? null : this);
|
||||||
mPinnedKeys.setVisibility(hideToolbarKeys ? GONE : mSuggestionsStrip.getVisibility());
|
mPinnedKeys.setVisibility(hideToolbarKeys ? GONE : mSuggestionsStrip.getVisibility());
|
||||||
isInlineAutofillSuggestionsVisible = false;
|
isExternalSuggestionVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRtl(final boolean isRtlLanguage) {
|
public void setRtl(final boolean isRtlLanguage) {
|
||||||
|
@ -281,9 +278,9 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
|
||||||
getContext(), mSuggestedWords, mSuggestionsStrip, this);
|
getContext(), mSuggestedWords, mSuggestionsStrip, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInlineSuggestionsView(final View view) {
|
public void setExternalSuggestionView(final View view) {
|
||||||
clear();
|
clear();
|
||||||
isInlineAutofillSuggestionsVisible = true;
|
isExternalSuggestionVisible = true;
|
||||||
mSuggestionsStrip.addView(view);
|
mSuggestionsStrip.addView(view);
|
||||||
if (Settings.getInstance().getCurrent().mAutoHideToolbar)
|
if (Settings.getInstance().getCurrent().mAutoHideToolbar)
|
||||||
setToolbarVisibility(false);
|
setToolbarVisibility(false);
|
||||||
|
@ -548,7 +545,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
|
||||||
public boolean onInterceptTouchEvent(final MotionEvent me) {
|
public boolean onInterceptTouchEvent(final MotionEvent me) {
|
||||||
|
|
||||||
// Disable More Suggestions if inline autofill suggestions is visible
|
// Disable More Suggestions if inline autofill suggestions is visible
|
||||||
if(isInlineAutofillSuggestionsVisible) {
|
if(isExternalSuggestionVisible) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ public final class InputTypeUtils implements InputType {
|
||||||
TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
|
TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
|
||||||
private static final int TEXT_VISIBLE_PASSWORD_INPUT_TYPE =
|
private static final int TEXT_VISIBLE_PASSWORD_INPUT_TYPE =
|
||||||
TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
|
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 = {
|
private static final int[] SUPPRESSING_AUTO_SPACES_FIELD_VARIATION = {
|
||||||
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS,
|
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS,
|
||||||
InputType.TYPE_TEXT_VARIATION_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;
|
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) {
|
public static boolean isEmailVariation(final int variation) {
|
||||||
return variation == TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
return variation == TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
||||||
|| isWebEmailAddressVariation(variation);
|
|| isWebEmailAddressVariation(variation);
|
||||||
|
|
|
@ -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>
|
31
app/src/main/res/layout/clipboard_suggestion.xml
Normal file
31
app/src/main/res/layout/clipboard_suggestion.xml
Normal 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>
|
|
@ -51,6 +51,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
android:hapticFeedbackEnabled="false"
|
android:hapticFeedbackEnabled="false"
|
||||||
android:soundEffectsEnabled="false" />
|
android:soundEffectsEnabled="false" />
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
|
@ -96,6 +96,9 @@
|
||||||
<dimen name="config_more_suggestions_modal_tolerance">32.0dp</dimen>
|
<dimen name="config_more_suggestions_modal_tolerance">32.0dp</dimen>
|
||||||
<fraction name="config_more_suggestions_info_ratio">18%</fraction>
|
<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 -->
|
<!-- Common gesture trail parameters -->
|
||||||
<!-- Minimum distance between gesture trail sampling points. -->
|
<!-- Minimum distance between gesture trail sampling points. -->
|
||||||
<dimen name="config_gesture_trail_min_sampling_distance">9.6dp</dimen>
|
<dimen name="config_gesture_trail_min_sampling_distance">9.6dp</dimen>
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
<!-- Spoken description of a suggestion when nothing is specified and the field is blank. -->
|
<!-- Spoken description of a suggestion when nothing is specified and the field is blank. -->
|
||||||
<string name="spoken_empty_suggestion">No suggestion</string>
|
<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. -->
|
<!-- Spoken description for unknown keyboard keys. -->
|
||||||
<string name="spoken_description_unknown">Unknown character</string>
|
<string name="spoken_description_unknown">Unknown character</string>
|
||||||
|
|
|
@ -134,6 +134,10 @@
|
||||||
<string name="bigram_prediction">Next-word suggestions</string>
|
<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. -->
|
<!-- 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>
|
<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]-->
|
<!-- 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>
|
<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]-->
|
<!-- 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]-->
|
||||||
|
|
|
@ -108,6 +108,13 @@
|
||||||
android:defaultValue="@bool/config_center_suggestion_text_to_enter"
|
android:defaultValue="@bool/config_center_suggestion_text_to_enter"
|
||||||
android:persistent="true" />
|
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
|
<SwitchPreference
|
||||||
android:key="use_contacts"
|
android:key="use_contacts"
|
||||||
android:title="@string/use_contacts_dict"
|
android:title="@string/use_contacts_dict"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue