upgrade build.gradle and do some code inspection stuff

This commit is contained in:
Helium314 2024-05-15 22:47:24 +02:00
parent f825436449
commit 528bbb4f7f
33 changed files with 192 additions and 256 deletions

View file

@ -90,14 +90,22 @@ android {
} }
dependencies { dependencies {
implementation 'androidx.core:core-ktx:1.12.0' // androidx
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.preference:preference:1.2.1' implementation 'androidx.preference:preference:1.2.1'
implementation 'androidx.recyclerview:recyclerview:1.3.2' implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3"
implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.1.0'
implementation 'androidx.autofill:autofill:1.1.0' implementation 'androidx.autofill:autofill:1.1.0'
// kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3"
// when kotlin-serialization is enabled, Android Studio stops complaining about "Unresolved reference: serializer", but the build fails
// implementation "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
// color picker for user-defined colors
implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.1.0'
// test
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:5.11.0' testImplementation 'org.mockito:mockito-core:5.11.0'
testImplementation 'org.mockito:mockito-inline:5.2.0' testImplementation 'org.mockito:mockito-inline:5.2.0'

View file

@ -7,7 +7,6 @@
package helium314.keyboard.accessibility package helium314.keyboard.accessibility
import android.content.Context import android.content.Context
import android.media.AudioDeviceInfo
import android.media.AudioDeviceInfo.* import android.media.AudioDeviceInfo.*
import android.media.AudioManager import android.media.AudioManager
import android.os.Build import android.os.Build

View file

@ -47,10 +47,9 @@ open class KeyboardAccessibilityDelegate<KV : KeyboardView>(
/** /**
* Called when the keyboard layout changes. * Called when the keyboard layout changes.
* *
*
* **Note:** This method will be called even if accessibility is not * **Note:** This method will be called even if accessibility is not
* enabled. * enabled.
* @param keyboard The keyboard that is being set to the wrapping view. * [keyboard]: The keyboard that is being set to the wrapping view.
*/ */
open var keyboard: Keyboard? open var keyboard: Keyboard?
get() = mKeyboard get() = mKeyboard

View file

@ -116,8 +116,7 @@ class MainKeyboardAccessibilityDelegate(
*/ */
private fun announceKeyboardType(keyboard: Keyboard, lastKeyboard: Keyboard) { private fun announceKeyboardType(keyboard: Keyboard, lastKeyboard: Keyboard) {
val lastElementId = lastKeyboard.mId.mElementId val lastElementId = lastKeyboard.mId.mElementId
val resId: Int val resId = when (keyboard.mId.mElementId) {
resId = when (keyboard.mId.mElementId) {
KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED, KeyboardId.ELEMENT_ALPHABET -> { KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED, KeyboardId.ELEMENT_ALPHABET -> {
if (lastElementId == KeyboardId.ELEMENT_ALPHABET if (lastElementId == KeyboardId.ELEMENT_ALPHABET
|| lastElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { || lastElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {

View file

@ -9,7 +9,6 @@ package helium314.keyboard.event
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.TextUtils import android.text.TextUtils
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
import helium314.keyboard.latin.common.Constants
import java.util.* import java.util.*
/** /**
@ -23,6 +22,12 @@ import java.util.*
* finished combining part, will be shown normally as the composing string, while the second is * finished combining part, will be shown normally as the composing string, while the second is
* feedback on the composing state and will typically be shown with different styling such as * feedback on the composing state and will typically be shown with different styling such as
* a colored background. * a colored background.
*
* The combiner chain takes events as inputs and outputs code points and combining state.
* For example, if the input language is Japanese, the combining chain will typically perform
* kana conversion. This takes a string for initial text, taken to be present before the
* cursor: we'll start after this.
* @param initialText The text that has already been combined so far.
*/ */
class CombinerChain(initialText: String) { class CombinerChain(initialText: String) {
// The already combined text, as described above // The already combined text, as described above
@ -45,16 +50,6 @@ class CombinerChain(initialText: String) {
mCombiners.add(HangulCombiner()) mCombiners.add(HangulCombiner())
} }
/**
* Create an combiner chain.
*
* The combiner chain takes events as inputs and outputs code points and combining state.
* For example, if the input language is Japanese, the combining chain will typically perform
* kana conversion. This takes a string for initial text, taken to be present before the
* cursor: we'll start after this.
*
* @param initialText The text that has already been combined so far.
*/
init { init {
// The dead key combiner is always active, and always first // The dead key combiner is always active, and always first
mCombiners.add(DeadKeyCombiner()) mCombiners.add(DeadKeyCombiner())

View file

@ -28,7 +28,7 @@ class InputTransaction(// Initial conditions
* @param updateType What type of shift update this requires. * @param updateType What type of shift update this requires.
*/ */
fun requireShiftUpdate(updateType: Int) { fun requireShiftUpdate(updateType: Int) {
requiredShiftUpdate = Math.max(requiredShiftUpdate, updateType) requiredShiftUpdate = requiredShiftUpdate.coerceAtLeast(updateType)
} }
/** /**

View file

@ -191,7 +191,7 @@ public class Key implements Comparable<Key> {
/** /**
* Constructor for a key on <code>PopupKeyKeyboard</code> and on <code>MoreSuggestions</code>. * Constructor for a key on <code>PopupKeyKeyboard</code> and on <code>MoreSuggestions</code>.
*/ */
public Key(@Nullable final String label, final String iconName, final int code, public Key(@Nullable final String label, @NonNull final String iconName, final int code,
@Nullable final String outputText, @Nullable final String hintLabel, @Nullable final String outputText, @Nullable final String hintLabel,
final int labelFlags, final int backgroundType, final int x, final int y, final int labelFlags, final int backgroundType, final int x, final int y,
final int width, final int height, final int horizontalGap, final int verticalGap) { final int width, final int height, final int horizontalGap, final int verticalGap) {
@ -404,7 +404,7 @@ public class Key implements Comparable<Key> {
&& o.mCode == mCode && o.mCode == mCode
&& TextUtils.equals(o.mLabel, mLabel) && TextUtils.equals(o.mLabel, mLabel)
&& TextUtils.equals(o.mHintLabel, mHintLabel) && TextUtils.equals(o.mHintLabel, mHintLabel)
&& o.mIconName == mIconName && o.mIconName.equals(mIconName)
&& o.mBackgroundType == mBackgroundType && o.mBackgroundType == mBackgroundType
&& Arrays.equals(o.mPopupKeys, mPopupKeys) && Arrays.equals(o.mPopupKeys, mPopupKeys)
&& TextUtils.equals(o.getOutputText(), getOutputText()) && TextUtils.equals(o.getOutputText(), getOutputText())
@ -429,6 +429,7 @@ public class Key implements Comparable<Key> {
return o instanceof Key && equalsInternal((Key)o); return o instanceof Key && equalsInternal((Key)o);
} }
@NonNull
@Override @Override
public String toString() { public String toString() {
return toShortString() + " " + getX() + "," + getY() + " " + getWidth() + "x" + getHeight(); return toShortString() + " " + getX() + "," + getY() + " " + getWidth() + "x" + getHeight();
@ -654,7 +655,7 @@ public class Key implements Comparable<Key> {
return (mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0; return (mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0;
} }
private final boolean isShiftedLetterActivated() { private boolean isShiftedLetterActivated() {
return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0 return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0
&& !TextUtils.isEmpty(mHintLabel); && !TextUtils.isEmpty(mHintLabel);
} }

View file

@ -35,11 +35,11 @@ public interface KeyboardActionListener {
* Send a key code to the listener. * Send a key code to the listener.
* *
* @param primaryCode this is the code of the key that was pressed * @param primaryCode this is the code of the key that was pressed
* @param x x-coordinate pixel of touched event. If {@link #onCodeInput} is not called by * @param x x-coordinate pixel of touched event. If onCodeInput is not called by
* {@link PointerTracker} or so, the value should be * {@link PointerTracker} or so, the value should be
* {@link Constants#NOT_A_COORDINATE}. If it's called on insertion from the * {@link Constants#NOT_A_COORDINATE}. If it's called on insertion from the
* suggestion strip, it should be {@link Constants#SUGGESTION_STRIP_COORDINATE}. * suggestion strip, it should be {@link Constants#SUGGESTION_STRIP_COORDINATE}.
* @param y y-coordinate pixel of touched event. If {@link #onCodeInput} is not called by * @param y y-coordinate pixel of touched event. If #onCodeInput is not called by
* {@link PointerTracker} or so, the value should be * {@link PointerTracker} or so, the value should be
* {@link Constants#NOT_A_COORDINATE}.If it's called on insertion from the * {@link Constants#NOT_A_COORDINATE}.If it's called on insertion from the
* suggestion strip, it should be {@link Constants#SUGGESTION_STRIP_COORDINATE}. * suggestion strip, it should be {@link Constants#SUGGESTION_STRIP_COORDINATE}.
@ -103,9 +103,9 @@ public interface KeyboardActionListener {
KeyboardActionListener EMPTY_LISTENER = new Adapter(); KeyboardActionListener EMPTY_LISTENER = new Adapter();
static int SWIPE_NO_ACTION = 0; int SWIPE_NO_ACTION = 0;
static int SWIPE_MOVE_CURSOR = 1; int SWIPE_MOVE_CURSOR = 1;
static int SWIPE_SWITCH_LANGUAGE = 2; int SWIPE_SWITCH_LANGUAGE = 2;
class Adapter implements KeyboardActionListener { class Adapter implements KeyboardActionListener {
@Override @Override

View file

@ -97,9 +97,9 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
return true return true
} }
private fun onMoveCursorHorizontally(_steps: Int): Boolean { private fun onMoveCursorHorizontally(rawSteps: Int): Boolean {
if (_steps == 0) return false if (rawSteps == 0) return false
var steps = _steps var steps = rawSteps
// for RTL languages we want to invert pointer movement // for RTL languages we want to invert pointer movement
if (RichInputMethodManager.getInstance().currentSubtype.isRtlSubtype) steps = -steps if (RichInputMethodManager.getInstance().currentSubtype.isRtlSubtype) steps = -steps
val moveSteps: Int val moveSteps: Int

View file

@ -32,6 +32,7 @@ import helium314.keyboard.latin.utils.getCodeForToolbarKey
import helium314.keyboard.latin.utils.getCodeForToolbarKeyLongClick import helium314.keyboard.latin.utils.getCodeForToolbarKeyLongClick
import helium314.keyboard.latin.utils.getEnabledClipboardToolbarKeys import helium314.keyboard.latin.utils.getEnabledClipboardToolbarKeys
@SuppressLint("CustomViewStyleable")
class ClipboardHistoryView @JvmOverloads constructor( class ClipboardHistoryView @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet?, attrs: AttributeSet?,
@ -160,7 +161,7 @@ class ClipboardHistoryView @JvmOverloads constructor(
private fun setupToolbarKeys() { private fun setupToolbarKeys() {
// set layout params // set layout params
val toolbarKeyLayoutParams = LayoutParams(getResources().getDimensionPixelSize(R.dimen.config_suggestions_strip_edge_key_width), LayoutParams.MATCH_PARENT) val toolbarKeyLayoutParams = LayoutParams(resources.getDimensionPixelSize(R.dimen.config_suggestions_strip_edge_key_width), LayoutParams.MATCH_PARENT)
toolbarKeys.forEach { it.layoutParams = toolbarKeyLayoutParams } toolbarKeys.forEach { it.layoutParams = toolbarKeyLayoutParams }
} }

View file

@ -236,8 +236,7 @@ final class DynamicGridKeyboard extends Keyboard {
if (o instanceof Integer) { if (o instanceof Integer) {
final int code = (Integer)o; final int code = (Integer)o;
key = getKeyByCode(keyboards, code); key = getKeyByCode(keyboards, code);
} else if (o instanceof String) { } else if (o instanceof final String outputText) {
final String outputText = (String)o;
key = getKeyByOutputText(keyboards, outputText); key = getKeyByOutputText(keyboards, outputText);
} else { } else {
Log.w(TAG, "Invalid object: " + o); Log.w(TAG, "Invalid object: " + o);
@ -267,18 +266,20 @@ final class DynamicGridKeyboard extends Keyboard {
return row * mVerticalStep + mVerticalGap / 2; return row * mVerticalStep + mVerticalGap / 2;
} }
@NonNull
@Override @Override
public List<Key> getSortedKeys() { public List<Key> getSortedKeys() {
synchronized (mLock) { synchronized (mLock) {
if (mCachedGridKeys != null) { if (mCachedGridKeys != null) {
return mCachedGridKeys; return mCachedGridKeys;
} }
final ArrayList<Key> cachedKeys = new ArrayList<Key>(mGridKeys); final ArrayList<Key> cachedKeys = new ArrayList<>(mGridKeys);
mCachedGridKeys = Collections.unmodifiableList(cachedKeys); mCachedGridKeys = Collections.unmodifiableList(cachedKeys);
return mCachedGridKeys; return mCachedGridKeys;
} }
} }
@NonNull
@Override @Override
public List<Key> getNearestKeys(final int x, final int y) { public List<Key> getNearestKeys(final int x, final int y) {
// TODO: Calculate the nearest key index in mGridKeys from x and y. // TODO: Calculate the nearest key index in mGridKeys from x and y.
@ -312,13 +313,13 @@ final class DynamicGridKeyboard extends Keyboard {
@Override @Override
public boolean equals(final Object o) { public boolean equals(final Object o) {
if (!(o instanceof Key)) return false; if (!(o instanceof final Key key)) return false;
final Key key = (Key)o;
if (getCode() != key.getCode()) return false; if (getCode() != key.getCode()) return false;
if (!TextUtils.equals(getLabel(), key.getLabel())) return false; if (!TextUtils.equals(getLabel(), key.getLabel())) return false;
return TextUtils.equals(getOutputText(), key.getOutputText()); return TextUtils.equals(getOutputText(), key.getOutputText());
} }
@NonNull
@Override @Override
public String toString() { public String toString() {
return "GridKey: " + super.toString(); return "GridKey: " + super.toString();

View file

@ -121,6 +121,7 @@ object RawKeyboardParser {
else -> params.mId.mSubtype.keyboardLayoutSetName.substringBeforeLast("+") else -> params.mId.mSubtype.keyboardLayoutSetName.substringBeforeLast("+")
} }
// todo (later, see also keyboardParser): use Settings.getInstance().current.mSingleFunctionalLayout
private fun getFunctionalLayoutName(params: KeyboardParams) = when (params.mId.mElementId) { private fun getFunctionalLayoutName(params: KeyboardParams) = when (params.mId.mElementId) {
KeyboardId.ELEMENT_SYMBOLS_SHIFTED -> FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED KeyboardId.ELEMENT_SYMBOLS_SHIFTED -> FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED
KeyboardId.ELEMENT_SYMBOLS -> FUNCTIONAL_LAYOUT_SYMBOLS KeyboardId.ELEMENT_SYMBOLS -> FUNCTIONAL_LAYOUT_SYMBOLS

View file

@ -18,7 +18,7 @@ import helium314.keyboard.latin.settings.SettingsValues;
/** /**
* This class gathers audio feedback and haptic feedback functions. * This class gathers audio feedback and haptic feedback functions.
* * <p>
* It offers a consistent and simple interface that allows LatinIME to forget about the * It offers a consistent and simple interface that allows LatinIME to forget about the
* complexity of settings and the like. * complexity of settings and the like.
*/ */
@ -81,21 +81,12 @@ public final class AudioAndHapticFeedbackManager {
if (!mSoundOn) { if (!mSoundOn) {
return; return;
} }
final int sound; final int sound = switch (code) {
switch (code) { case KeyCode.DELETE -> AudioManager.FX_KEYPRESS_DELETE;
case KeyCode.DELETE: case Constants.CODE_ENTER -> AudioManager.FX_KEYPRESS_RETURN;
sound = AudioManager.FX_KEYPRESS_DELETE; case Constants.CODE_SPACE -> AudioManager.FX_KEYPRESS_SPACEBAR;
break; default -> AudioManager.FX_KEYPRESS_STANDARD;
case Constants.CODE_ENTER: };
sound = AudioManager.FX_KEYPRESS_RETURN;
break;
case Constants.CODE_SPACE:
sound = AudioManager.FX_KEYPRESS_SPACEBAR;
break;
default:
sound = AudioManager.FX_KEYPRESS_STANDARD;
break;
}
mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume); mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume);
} }

View file

@ -25,7 +25,7 @@ import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Manages all interactions with Contacts DB. * Manages all interactions with Contacts DB.
* * <p>
* The manager provides an API for listening to meaning full updates by keeping a * The manager provides an API for listening to meaning full updates by keeping a
* measure of the current state of the content provider. * measure of the current state of the content provider.
*/ */
@ -65,7 +65,7 @@ public class ContactsManager {
* - How many times it has been contacted * - How many times it has been contacted
* - How long since the last contact. * - How long since the last contact.
* - Whether the contact is in the visible group (i.e., Contacts list). * - Whether the contact is in the visible group (i.e., Contacts list).
* * <p>
* Note: This affinity is limited by the fact that some apps currently do not update the * Note: This affinity is limited by the fact that some apps currently do not update the
* LAST_TIME_CONTACTED or TIMES_CONTACTED counters. As a result, a frequently messaged * LAST_TIME_CONTACTED or TIMES_CONTACTED counters. As a result, a frequently messaged
* contact may still have 0 affinity. * contact may still have 0 affinity.
@ -101,13 +101,13 @@ public class ContactsManager {
* The number of contacts observed in the most recent instance of * The number of contacts observed in the most recent instance of
* contacts content provider. * contacts content provider.
*/ */
private AtomicInteger mContactCountAtLastRebuild = new AtomicInteger(0); private final AtomicInteger mContactCountAtLastRebuild = new AtomicInteger(0);
/** /**
* The hash code of list of valid contacts names in the most recent dictionary * The hash code of list of valid contacts names in the most recent dictionary
* rebuild. * rebuild.
*/ */
private AtomicInteger mHashCodeAtLastRebuild = new AtomicInteger(0); private final AtomicInteger mHashCodeAtLastRebuild = new AtomicInteger(0);
private final Context mContext; private final Context mContext;
private final ContactsContentObserver mObserver; private final ContactsContentObserver mObserver;
@ -134,7 +134,7 @@ public class ContactsManager {
* Returns all the valid names in the Contacts DB. Callers should also * Returns all the valid names in the Contacts DB. Callers should also
* call {@link #updateLocalState(ArrayList)} after they are done with result * call {@link #updateLocalState(ArrayList)} after they are done with result
* so that the manager can cache local state for determining updates. * so that the manager can cache local state for determining updates.
* * <p>
* These names are sorted by their affinity to the user, with favorite * These names are sorted by their affinity to the user, with favorite
* contacts appearing first. * contacts appearing first.
*/ */
@ -183,22 +183,15 @@ public class ContactsManager {
* Returns the number of contacts in contacts content provider. * Returns the number of contacts in contacts content provider.
*/ */
public int getContactCount() { public int getContactCount() {
// TODO: consider switching to a rawQuery("select count(*)...") on the database if // TODO: consider switching to a rawQuery("select count(*)...") on the database if performance is a bottleneck.
// performance is a bottleneck. try (Cursor cursor = mContext.getContentResolver().query(Contacts.CONTENT_URI,
Cursor cursor = null; ContactsDictionaryConstants.PROJECTION_ID_ONLY, null, null, null)
try { ) {
cursor = mContext.getContentResolver().query(Contacts.CONTENT_URI, if (null == cursor)
ContactsDictionaryConstants.PROJECTION_ID_ONLY, null, null, null);
if (null == cursor) {
return 0; return 0;
}
return cursor.getCount(); return cursor.getCount();
} catch (final SQLiteException e) { } catch (final SQLiteException e) {
Log.e(TAG, "SQLiteException in the remote Contacts process.", e); Log.e(TAG, "SQLiteException in the remote Contacts process.", e);
} finally {
if (null != cursor) {
cursor.close();
}
} }
return 0; return 0;
} }

View file

@ -20,6 +20,8 @@ import java.util.Arrays;
import static helium314.keyboard.latin.common.Constants.ImeOption.NO_FLOATING_GESTURE_PREVIEW; import static helium314.keyboard.latin.common.Constants.ImeOption.NO_FLOATING_GESTURE_PREVIEW;
import static helium314.keyboard.latin.common.Constants.ImeOption.NO_MICROPHONE; import static helium314.keyboard.latin.common.Constants.ImeOption.NO_MICROPHONE;
import androidx.annotation.NonNull;
/** /**
* Class to hold attributes of the input field. * Class to hold attributes of the input field.
*/ */
@ -162,92 +164,60 @@ public final class InputAttributes {
} }
private static String toInputClassString(final int inputClass) { private static String toInputClassString(final int inputClass) {
switch (inputClass) { return switch (inputClass) {
case InputType.TYPE_CLASS_TEXT: case InputType.TYPE_CLASS_TEXT -> "TYPE_CLASS_TEXT";
return "TYPE_CLASS_TEXT"; case InputType.TYPE_CLASS_PHONE -> "TYPE_CLASS_PHONE";
case InputType.TYPE_CLASS_PHONE: case InputType.TYPE_CLASS_NUMBER -> "TYPE_CLASS_NUMBER";
return "TYPE_CLASS_PHONE"; case InputType.TYPE_CLASS_DATETIME -> "TYPE_CLASS_DATETIME";
case InputType.TYPE_CLASS_NUMBER: default -> String.format("unknownInputClass<0x%08x>", inputClass);
return "TYPE_CLASS_NUMBER"; };
case InputType.TYPE_CLASS_DATETIME:
return "TYPE_CLASS_DATETIME";
default:
return String.format("unknownInputClass<0x%08x>", inputClass);
}
} }
private static String toVariationString(final int inputClass, final int variation) { private static String toVariationString(final int inputClass, final int variation) {
switch (inputClass) { return switch (inputClass) {
case InputType.TYPE_CLASS_TEXT: case InputType.TYPE_CLASS_TEXT -> toTextVariationString(variation);
return toTextVariationString(variation); case InputType.TYPE_CLASS_NUMBER -> toNumberVariationString(variation);
case InputType.TYPE_CLASS_NUMBER: case InputType.TYPE_CLASS_DATETIME -> toDatetimeVariationString(variation);
return toNumberVariationString(variation); default -> "";
case InputType.TYPE_CLASS_DATETIME: };
return toDatetimeVariationString(variation);
default:
return "";
}
} }
private static String toTextVariationString(final int variation) { private static String toTextVariationString(final int variation) {
switch (variation) { return switch (variation) {
case InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS: case InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS -> " TYPE_TEXT_VARIATION_EMAIL_ADDRESS";
return " TYPE_TEXT_VARIATION_EMAIL_ADDRESS"; case InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT -> "TYPE_TEXT_VARIATION_EMAIL_SUBJECT";
case InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT: case InputType.TYPE_TEXT_VARIATION_FILTER -> "TYPE_TEXT_VARIATION_FILTER";
return "TYPE_TEXT_VARIATION_EMAIL_SUBJECT"; case InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE -> "TYPE_TEXT_VARIATION_LONG_MESSAGE";
case InputType.TYPE_TEXT_VARIATION_FILTER: case InputType.TYPE_TEXT_VARIATION_NORMAL -> "TYPE_TEXT_VARIATION_NORMAL";
return "TYPE_TEXT_VARIATION_FILTER"; case InputType.TYPE_TEXT_VARIATION_PASSWORD -> "TYPE_TEXT_VARIATION_PASSWORD";
case InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE: case InputType.TYPE_TEXT_VARIATION_PERSON_NAME -> "TYPE_TEXT_VARIATION_PERSON_NAME";
return "TYPE_TEXT_VARIATION_LONG_MESSAGE"; case InputType.TYPE_TEXT_VARIATION_PHONETIC -> "TYPE_TEXT_VARIATION_PHONETIC";
case InputType.TYPE_TEXT_VARIATION_NORMAL: case InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS -> "TYPE_TEXT_VARIATION_POSTAL_ADDRESS";
return "TYPE_TEXT_VARIATION_NORMAL"; case InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE -> "TYPE_TEXT_VARIATION_SHORT_MESSAGE";
case InputType.TYPE_TEXT_VARIATION_PASSWORD: case InputType.TYPE_TEXT_VARIATION_URI -> "TYPE_TEXT_VARIATION_URI";
return "TYPE_TEXT_VARIATION_PASSWORD"; case InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD -> "TYPE_TEXT_VARIATION_VISIBLE_PASSWORD";
case InputType.TYPE_TEXT_VARIATION_PERSON_NAME: case InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT -> "TYPE_TEXT_VARIATION_WEB_EDIT_TEXT";
return "TYPE_TEXT_VARIATION_PERSON_NAME"; case InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS -> "TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS";
case InputType.TYPE_TEXT_VARIATION_PHONETIC: case InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD -> "TYPE_TEXT_VARIATION_WEB_PASSWORD";
return "TYPE_TEXT_VARIATION_PHONETIC"; default -> String.format("unknownVariation<0x%08x>", variation);
case InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS: };
return "TYPE_TEXT_VARIATION_POSTAL_ADDRESS";
case InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE:
return "TYPE_TEXT_VARIATION_SHORT_MESSAGE";
case InputType.TYPE_TEXT_VARIATION_URI:
return "TYPE_TEXT_VARIATION_URI";
case InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD:
return "TYPE_TEXT_VARIATION_VISIBLE_PASSWORD";
case InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT:
return "TYPE_TEXT_VARIATION_WEB_EDIT_TEXT";
case InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS:
return "TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS";
case InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD:
return "TYPE_TEXT_VARIATION_WEB_PASSWORD";
default:
return String.format("unknownVariation<0x%08x>", variation);
}
} }
private static String toNumberVariationString(final int variation) { private static String toNumberVariationString(final int variation) {
switch (variation) { return switch (variation) {
case InputType.TYPE_NUMBER_VARIATION_NORMAL: case InputType.TYPE_NUMBER_VARIATION_NORMAL -> "TYPE_NUMBER_VARIATION_NORMAL";
return "TYPE_NUMBER_VARIATION_NORMAL"; case InputType.TYPE_NUMBER_VARIATION_PASSWORD -> "TYPE_NUMBER_VARIATION_PASSWORD";
case InputType.TYPE_NUMBER_VARIATION_PASSWORD: default -> String.format("unknownVariation<0x%08x>", variation);
return "TYPE_NUMBER_VARIATION_PASSWORD"; };
default:
return String.format("unknownVariation<0x%08x>", variation);
}
} }
private static String toDatetimeVariationString(final int variation) { private static String toDatetimeVariationString(final int variation) {
switch (variation) { return switch (variation) {
case InputType.TYPE_DATETIME_VARIATION_NORMAL: case InputType.TYPE_DATETIME_VARIATION_NORMAL -> "TYPE_DATETIME_VARIATION_NORMAL";
return "TYPE_DATETIME_VARIATION_NORMAL"; case InputType.TYPE_DATETIME_VARIATION_DATE -> "TYPE_DATETIME_VARIATION_DATE";
case InputType.TYPE_DATETIME_VARIATION_DATE: case InputType.TYPE_DATETIME_VARIATION_TIME -> "TYPE_DATETIME_VARIATION_TIME";
return "TYPE_DATETIME_VARIATION_DATE"; default -> String.format("unknownVariation<0x%08x>", variation);
case InputType.TYPE_DATETIME_VARIATION_TIME: };
return "TYPE_DATETIME_VARIATION_TIME";
default:
return String.format("unknownVariation<0x%08x>", variation);
}
} }
private static String toFlagsString(final int flags) { private static String toFlagsString(final int flags) {
@ -272,6 +242,7 @@ public final class InputAttributes {
} }
// Pretty print // Pretty print
@NonNull
@Override @Override
public String toString() { public String toString() {
return String.format( return String.format(

View file

@ -6,6 +6,7 @@
package helium314.keyboard.latin; package helium314.keyboard.latin;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -783,6 +784,7 @@ public class LatinIME extends InputMethodService implements
* Starts from {@link android.os.Build.VERSION_CODES#S_V2}, the returning context object has * Starts from {@link android.os.Build.VERSION_CODES#S_V2}, the returning context object has
* became to IME context self since it ends up capable of updating its resources internally. * became to IME context self since it ends up capable of updating its resources internally.
*/ */
@SuppressWarnings("deprecation")
private @NonNull Context getDisplayContext() { private @NonNull Context getDisplayContext() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) {
// IME context sources is now managed by WindowProviderService from Android 12L. // IME context sources is now managed by WindowProviderService from Android 12L.
@ -1104,10 +1106,6 @@ public class LatinIME extends InputMethodService implements
} }
} }
public CharSequence getSelection() {
return mInputLogic.mConnection.getSelectedText(0);
}
/** /**
* This is called when the user has clicked on the extracted text view, * This is called when the user has clicked on the extracted text view,
* when running in fullscreen mode. The default implementation hides * when running in fullscreen mode. The default implementation hides
@ -1667,14 +1665,11 @@ public class LatinIME extends InputMethodService implements
*/ */
private void updateStateAfterInputTransaction(final InputTransaction inputTransaction) { private void updateStateAfterInputTransaction(final InputTransaction inputTransaction) {
switch (inputTransaction.getRequiredShiftUpdate()) { switch (inputTransaction.getRequiredShiftUpdate()) {
case InputTransaction.SHIFT_UPDATE_LATER: case InputTransaction.SHIFT_UPDATE_LATER -> mHandler.postUpdateShiftState();
mHandler.postUpdateShiftState(); case InputTransaction.SHIFT_UPDATE_NOW -> mKeyboardSwitcher
break; .requestUpdatingShiftState(getCurrentAutoCapsState(), getCurrentRecapitalizeState());
case InputTransaction.SHIFT_UPDATE_NOW: default -> {
mKeyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(), } // SHIFT_NO_UPDATE
getCurrentRecapitalizeState());
break;
default: // SHIFT_NO_UPDATE
} }
if (inputTransaction.requiresUpdateSuggestions()) { if (inputTransaction.requiresUpdateSuggestions()) {
final int inputStyle; final int inputStyle;
@ -1897,6 +1892,7 @@ public class LatinIME extends InputMethodService implements
} }
} }
@SuppressLint("SwitchIntDef")
@Override @Override
public void onTrimMemory(int level) { public void onTrimMemory(int level) {
super.onTrimMemory(level); super.onTrimMemory(level);

View file

@ -6,11 +6,11 @@
package helium314.keyboard.latin; package helium314.keyboard.latin;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import helium314.keyboard.keyboard.internal.KeySpecParser; import helium314.keyboard.keyboard.internal.KeySpecParser;
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode;
import helium314.keyboard.latin.common.Constants;
import helium314.keyboard.latin.common.StringUtils; import helium314.keyboard.latin.common.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
@ -18,7 +18,7 @@ import java.util.Arrays;
/** /**
* The extended {@link SuggestedWords} class to represent punctuation suggestions. * The extended {@link SuggestedWords} class to represent punctuation suggestions.
* * <p>
* Each punctuation specification string is the key specification that can be parsed by * Each punctuation specification string is the key specification that can be parsed by
* {@link KeySpecParser}. * {@link KeySpecParser}.
*/ */
@ -44,7 +44,7 @@ public final class PunctuationSuggestions extends SuggestedWords {
public static PunctuationSuggestions newPunctuationSuggestions( public static PunctuationSuggestions newPunctuationSuggestions(
@Nullable final String[] punctuationSpecs) { @Nullable final String[] punctuationSpecs) {
if (punctuationSpecs == null || punctuationSpecs.length == 0) { if (punctuationSpecs == null || punctuationSpecs.length == 0) {
return new PunctuationSuggestions(new ArrayList<SuggestedWordInfo>(0)); return new PunctuationSuggestions(new ArrayList<>(0));
} }
final ArrayList<SuggestedWordInfo> punctuationList = final ArrayList<SuggestedWordInfo> punctuationList =
new ArrayList<>(punctuationSpecs.length); new ArrayList<>(punctuationSpecs.length);
@ -99,7 +99,7 @@ public final class PunctuationSuggestions extends SuggestedWords {
} }
@Override @Override
public String toString() { @NonNull public String toString() {
return "PunctuationSuggestions: " return "PunctuationSuggestions: "
+ " words=" + Arrays.toString(mSuggestedWordInfoList.toArray()); + " words=" + Arrays.toString(mSuggestedWordInfoList.toArray());
} }

View file

@ -15,7 +15,6 @@ import helium314.keyboard.keyboard.KeyboardSwitcher;
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode;
import helium314.keyboard.latin.SuggestedWords.SuggestedWordInfo; import helium314.keyboard.latin.SuggestedWords.SuggestedWordInfo;
import helium314.keyboard.latin.common.ComposedData; import helium314.keyboard.latin.common.ComposedData;
import helium314.keyboard.latin.common.Constants;
import helium314.keyboard.latin.common.CoordinateUtils; import helium314.keyboard.latin.common.CoordinateUtils;
import helium314.keyboard.latin.common.InputPointers; import helium314.keyboard.latin.common.InputPointers;
import helium314.keyboard.latin.common.StringUtils; import helium314.keyboard.latin.common.StringUtils;
@ -167,7 +166,7 @@ public final class WordComposer {
/** /**
* Apply a processed input event. * Apply a processed input event.
* * <p>
* All input events should be supported, including software/hardware events, characters as well * All input events should be supported, including software/hardware events, characters as well
* as deletions, multiple inputs and gestures. * as deletions, multiple inputs and gestures.
* *
@ -320,7 +319,7 @@ public final class WordComposer {
/** /**
* Whether this composer is composing or about to compose a word in which only the first letter * Whether this composer is composing or about to compose a word in which only the first letter
* is a capital. * is a capital.
* * <p>
* If we do have a composing word, we just return whether the word has indeed only its first * If we do have a composing word, we just return whether the word has indeed only its first
* character capitalized. If we don't, then we return a value based on the capitalized mode, * character capitalized. If we don't, then we return a value based on the capitalized mode,
* which tell us what is likely to happen for the next composing word. * which tell us what is likely to happen for the next composing word.
@ -370,7 +369,7 @@ public final class WordComposer {
/** /**
* Saves the caps mode at the start of composing. * Saves the caps mode at the start of composing.
* * <p>
* WordComposer needs to know about the caps mode for several reasons. The first is, we need * WordComposer needs to know about the caps mode for several reasons. The first is, we need
* to know after the fact what the reason was, to register the correct form into the user * to know after the fact what the reason was, to register the correct form into the user
* history dictionary: if the word was automatically capitalized, we should insert it in * history dictionary: if the word was automatically capitalized, we should insert it in
@ -385,7 +384,7 @@ public final class WordComposer {
/** /**
* Before fetching suggestions, we don't necessarily know about the capitalized mode yet. * Before fetching suggestions, we don't necessarily know about the capitalized mode yet.
* * <p>
* If we don't have a composing word yet, we take a note of this mode so that we can then * If we don't have a composing word yet, we take a note of this mode so that we can then
* supply this information to the suggestion process. If we have a composing word, then * supply this information to the suggestion process. If we have a composing word, then
* the previous mode has priority over this. * the previous mode has priority over this.

View file

@ -58,7 +58,7 @@ object LocaleUtils {
// The compared locales are fully identical. This is the best match level. // The compared locales are fully identical. This is the best match level.
private const val LOCALE_FULL_MATCH = 30 private const val LOCALE_FULL_MATCH = 30
const val LOCALE_GOOD_MATCH = LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER; const val LOCALE_GOOD_MATCH = LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER
/** /**
* Return how well a tested locale matches a reference locale. * Return how well a tested locale matches a reference locale.

View file

@ -82,12 +82,8 @@ class InputLogicHandler implements Handler.Callback {
// Called on the Non-UI handler thread by the Handler code. // Called on the Non-UI handler thread by the Handler code.
@Override @Override
public boolean handleMessage(final Message msg) { public boolean handleMessage(final Message msg) {
switch (msg.what) { if (msg.what == MSG_GET_SUGGESTED_WORDS)
case MSG_GET_SUGGESTED_WORDS: mLatinIME.getSuggestedWords(msg.arg1, msg.arg2, (OnGetSuggestedWordsCallback) msg.obj);
mLatinIME.getSuggestedWords(msg.arg1 /* inputStyle */,
msg.arg2 /* sequenceNumber */, (OnGetSuggestedWordsCallback) msg.obj);
break;
}
return true; return true;
} }
@ -122,12 +118,7 @@ class InputLogicHandler implements Handler.Callback {
return; return;
} }
mInputLogic.mWordComposer.setBatchInputPointers(batchPointers); mInputLogic.mWordComposer.setBatchInputPointers(batchPointers);
final OnGetSuggestedWordsCallback callback = new OnGetSuggestedWordsCallback() { final OnGetSuggestedWordsCallback callback = suggestedWords -> showGestureSuggestionsWithPreviewVisuals(suggestedWords, isTailBatchInput);
@Override
public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
showGestureSuggestionsWithPreviewVisuals(suggestedWords, isTailBatchInput);
}
};
getSuggestedWords(isTailBatchInput ? SuggestedWords.INPUT_STYLE_TAIL_BATCH getSuggestedWords(isTailBatchInput ? SuggestedWords.INPUT_STYLE_TAIL_BATCH
: SuggestedWords.INPUT_STYLE_UPDATE_BATCH, sequenceNumber, callback); : SuggestedWords.INPUT_STYLE_UPDATE_BATCH, sequenceNumber, callback);
} }
@ -159,7 +150,7 @@ class InputLogicHandler implements Handler.Callback {
/** /**
* Update a batch input. * Update a batch input.
* * <p>
* This fetches suggestions and updates the suggestion strip and the floating text preview. * This fetches suggestions and updates the suggestion strip and the floating text preview.
* *
* @param batchPointers the updated batch pointers. * @param batchPointers the updated batch pointers.
@ -168,12 +159,12 @@ class InputLogicHandler implements Handler.Callback {
// Called on the UI thread by InputLogic. // Called on the UI thread by InputLogic.
public void onUpdateBatchInput(final InputPointers batchPointers, public void onUpdateBatchInput(final InputPointers batchPointers,
final int sequenceNumber) { final int sequenceNumber) {
updateBatchInput(batchPointers, sequenceNumber, false /* isTailBatchInput */); updateBatchInput(batchPointers, sequenceNumber, false);
} }
/** /**
* Cancel a batch input. * Cancel a batch input.
* * <p>
* Note that as opposed to updateTailBatchInput, we do the UI side of this immediately on the * Note that as opposed to updateTailBatchInput, we do the UI side of this immediately on the
* same thread, rather than get this to call a method in LatinIME. This is because * same thread, rather than get this to call a method in LatinIME. This is because
* canceling a batch input does not necessitate the long operation of pulling suggestions. * canceling a batch input does not necessitate the long operation of pulling suggestions.
@ -187,7 +178,7 @@ class InputLogicHandler implements Handler.Callback {
/** /**
* Trigger an update for a tail batch input. * Trigger an update for a tail batch input.
* * <p>
* A tail batch input is the last update for a gesture, the one that is triggered after the * A tail batch input is the last update for a gesture, the one that is triggered after the
* user lifts their finger. This method schedules fetching suggestions on the non-UI thread, * user lifts their finger. This method schedules fetching suggestions on the non-UI thread,
* then when the suggestions are computed it comes back on the UI thread to update the * then when the suggestions are computed it comes back on the UI thread to update the
@ -199,7 +190,7 @@ class InputLogicHandler implements Handler.Callback {
// Called on the UI thread by InputLogic. // Called on the UI thread by InputLogic.
public void updateTailBatchInput(final InputPointers batchPointers, public void updateTailBatchInput(final InputPointers batchPointers,
final int sequenceNumber) { final int sequenceNumber) {
updateBatchInput(batchPointers, sequenceNumber, true /* isTailBatchInput */); updateBatchInput(batchPointers, sequenceNumber, true);
} }
public void getSuggestedWords(final int inputStyle, final int sequenceNumber, public void getSuggestedWords(final int inputStyle, final int sequenceNumber,

View file

@ -6,6 +6,7 @@
package helium314.keyboard.latin.makedict; package helium314.keyboard.latin.makedict;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.BinaryDictionary;
@ -20,7 +21,7 @@ import java.util.Arrays;
/** /**
* Utility class for a word with a probability. * Utility class for a word with a probability.
* * <p>
* This is chiefly used to iterate a dictionary. * This is chiefly used to iterate a dictionary.
*/ */
public final class WordProperty implements Comparable<WordProperty> { public final class WordProperty implements Comparable<WordProperty> {
@ -150,7 +151,7 @@ public final class WordProperty implements Comparable<WordProperty> {
/** /**
* Three-way comparison. * Three-way comparison.
* * <p>
* A Word x is greater than a word y if x has a higher frequency. If they have the same * A Word x is greater than a word y if x has a higher frequency. If they have the same
* frequency, they are sorted in lexicographic order. * frequency, they are sorted in lexicographic order.
*/ */
@ -163,15 +164,14 @@ public final class WordProperty implements Comparable<WordProperty> {
/** /**
* Equality test. * Equality test.
* * <p>
* Words are equal if they have the same frequency, the same spellings, and the same * Words are equal if they have the same frequency, the same spellings, and the same
* attributes. * attributes.
*/ */
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == this) return true; if (o == this) return true;
if (!(o instanceof WordProperty)) return false; if (!(o instanceof WordProperty w)) return false;
WordProperty w = (WordProperty)o;
return mProbabilityInfo.equals(w.mProbabilityInfo) && mWord.equals(w.mWord) return mProbabilityInfo.equals(w.mProbabilityInfo) && mWord.equals(w.mWord)
&& mShortcutTargets.equals(w.mShortcutTargets) && equals(mNgrams, w.mNgrams) && mShortcutTargets.equals(w.mShortcutTargets) && equals(mNgrams, w.mNgrams)
&& mIsNotAWord == w.mIsNotAWord && mIsPossiblyOffensive == w.mIsPossiblyOffensive && mIsNotAWord == w.mIsNotAWord && mIsPossiblyOffensive == w.mIsPossiblyOffensive
@ -199,7 +199,7 @@ public final class WordProperty implements Comparable<WordProperty> {
} }
@Override @Override
public String toString() { @NonNull public String toString() {
return CombinedFormatUtils.formatWordProperty(this); return CombinedFormatUtils.formatWordProperty(this);
} }
} }

View file

@ -57,7 +57,7 @@ public final class PermissionsActivity
} }
@Override @Override
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putInt(EXTRA_PERMISSION_REQUEST_CODE, mPendingRequestCode); outState.putInt(EXTRA_PERMISSION_REQUEST_CODE, mPendingRequestCode);
} }
@ -68,8 +68,8 @@ public final class PermissionsActivity
// Only do request when there is no pending request to avoid duplicated requests. // Only do request when there is no pending request to avoid duplicated requests.
if (mPendingRequestCode == INVALID_REQUEST_CODE) { if (mPendingRequestCode == INVALID_REQUEST_CODE) {
final Bundle extras = getIntent().getExtras(); final Bundle extras = getIntent().getExtras();
final String[] permissionsToRequest = if (extras == null) return;
extras.getStringArray(EXTRA_PERMISSION_REQUESTED_PERMISSIONS); final String[] permissionsToRequest = extras.getStringArray(EXTRA_PERMISSION_REQUESTED_PERMISSIONS);
mPendingRequestCode = extras.getInt(EXTRA_PERMISSION_REQUEST_CODE); mPendingRequestCode = extras.getInt(EXTRA_PERMISSION_REQUEST_CODE);
// Assuming that all supplied permissions are not granted yet, so that we don't need to // Assuming that all supplied permissions are not granted yet, so that we don't need to
// check them again. // check them again.

View file

@ -73,6 +73,7 @@ import java.util.zip.ZipOutputStream
* - Improve keyboard * - Improve keyboard
* - Debug settings * - Debug settings
*/ */
@Suppress("KotlinConstantConditions") // build type might be a constant, but depends on... build type!
class AdvancedSettingsFragment : SubScreenFragment() { class AdvancedSettingsFragment : SubScreenFragment() {
private val libfile by lazy { File(requireContext().filesDir.absolutePath + File.separator + JniUtils.JNI_LIB_IMPORT_FILE_NAME) } private val libfile by lazy { File(requireContext().filesDir.absolutePath + File.separator + JniUtils.JNI_LIB_IMPORT_FILE_NAME) }
private val backupFilePatterns by lazy { listOf( private val backupFilePatterns by lazy { listOf(
@ -436,8 +437,8 @@ class AdvancedSettingsFragment : SubScreenFragment() {
} }
checkVersionUpgrade(requireContext()) checkVersionUpgrade(requireContext())
Settings.getInstance().startListener() Settings.getInstance().startListener()
val additionalSubtypes = Settings.readPrefAdditionalSubtypes(sharedPreferences, resources); val additionalSubtypes = Settings.readPrefAdditionalSubtypes(sharedPreferences, resources)
updateAdditionalSubtypes(AdditionalSubtypeUtils.createAdditionalSubtypesArray(additionalSubtypes)); updateAdditionalSubtypes(AdditionalSubtypeUtils.createAdditionalSubtypesArray(additionalSubtypes))
reloadEnabledSubtypes(requireContext()) reloadEnabledSubtypes(requireContext())
val newDictBroadcast = Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION) val newDictBroadcast = Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION)
activity?.sendBroadcast(newDictBroadcast) activity?.sendBroadcast(newDictBroadcast)

View file

@ -21,7 +21,6 @@ import helium314.keyboard.latin.R;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatTextView; import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.view.ViewCompat;
public final class SetupStartIndicatorView extends LinearLayout { public final class SetupStartIndicatorView extends LinearLayout {
public SetupStartIndicatorView(final Context context, final AttributeSet attrs) { public SetupStartIndicatorView(final Context context, final AttributeSet attrs) {
@ -72,13 +71,13 @@ public final class SetupStartIndicatorView extends LinearLayout {
@Override @Override
protected void onDraw(@NonNull final Canvas canvas) { protected void onDraw(@NonNull final Canvas canvas) {
super.onDraw(canvas); super.onDraw(canvas);
final int layoutDirection = ViewCompat.getLayoutDirection(this); final int layoutDirection = getLayoutDirection();
final int width = getWidth(); final int width = getWidth();
final int height = getHeight(); final int height = getHeight();
final float halfHeight = height / 2.0f; final float halfHeight = height / 2.0f;
final Path path = mIndicatorPath; final Path path = mIndicatorPath;
path.rewind(); path.rewind();
if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) { if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
// Left arrow // Left arrow
path.moveTo(width, 0.0f); path.moveTo(width, 0.0f);
path.lineTo(0.0f, halfHeight); path.lineTo(0.0f, halfHeight);

View file

@ -13,9 +13,9 @@ import android.graphics.Path;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import helium314.keyboard.latin.R; import androidx.annotation.NonNull;
import androidx.core.view.ViewCompat; import helium314.keyboard.latin.R;
public final class SetupStepIndicatorView extends View { public final class SetupStepIndicatorView extends View {
private final Path mIndicatorPath = new Path(); private final Path mIndicatorPath = new Path();
@ -29,17 +29,17 @@ public final class SetupStepIndicatorView extends View {
} }
public void setIndicatorPosition(final int stepPos, final int totalStepNum) { public void setIndicatorPosition(final int stepPos, final int totalStepNum) {
final int layoutDirection = ViewCompat.getLayoutDirection(this); final int layoutDirection = getLayoutDirection();
// The indicator position is the center of the partition that is equally divided into // The indicator position is the center of the partition that is equally divided into
// the total step number. // the total step number.
final float partionWidth = 1.0f / totalStepNum; final float partionWidth = 1.0f / totalStepNum;
final float pos = stepPos * partionWidth + partionWidth / 2.0f; final float pos = stepPos * partionWidth + partionWidth / 2.0f;
mXRatio = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) ? 1.0f - pos : pos; mXRatio = (layoutDirection == View.LAYOUT_DIRECTION_RTL) ? 1.0f - pos : pos;
invalidate(); invalidate();
} }
@Override @Override
protected void onDraw(final Canvas canvas) { protected void onDraw(@NonNull final Canvas canvas) {
super.onDraw(canvas); super.onDraw(canvas);
final int xPos = (int)(getWidth() * mXRatio); final int xPos = (int)(getWidth() * mXRatio);
final int height = getHeight(); final int height = getHeight();

View file

@ -7,10 +7,12 @@
package helium314.keyboard.latin.suggestions; package helium314.keyboard.latin.suggestions;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import helium314.keyboard.keyboard.Key; import helium314.keyboard.keyboard.Key;
import helium314.keyboard.keyboard.Keyboard; import helium314.keyboard.keyboard.Keyboard;
import helium314.keyboard.keyboard.internal.KeyboardBuilder; import helium314.keyboard.keyboard.internal.KeyboardBuilder;
@ -45,12 +47,11 @@ public final class MoreSuggestions extends Keyboard {
public int layout(final SuggestedWords suggestedWords, final int fromIndex, public int layout(final SuggestedWords suggestedWords, final int fromIndex,
final int maxWidth, final int minWidth, final int maxRow, final Paint paint, final int maxWidth, final int minWidth, final int maxRow, final Paint paint,
final Resources res) { final Context context) {
clearKeys(); clearKeys();
mDivider = res.getDrawable(R.drawable.more_suggestions_divider); mDivider = ContextCompat.getDrawable(context, R.drawable.more_suggestions_divider);
mDividerWidth = mDivider.getIntrinsicWidth(); mDividerWidth = mDivider == null ? 0 : mDivider.getIntrinsicWidth();
final float padding = res.getDimension( final float padding = context.getResources().getDimension(R.dimen.config_more_suggestions_key_horizontal_padding);
R.dimen.config_more_suggestions_key_horizontal_padding);
int row = 0; int row = 0;
int index = fromIndex; int index = fromIndex;
@ -186,7 +187,7 @@ public final class MoreSuggestions extends Keyboard {
mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2; mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2;
mPaneView.updateKeyboardGeometry(mParams.mDefaultAbsoluteRowHeight); mPaneView.updateKeyboardGeometry(mParams.mDefaultAbsoluteRowHeight);
final int count = mParams.layout(suggestedWords, fromIndex, maxWidth, minWidth, maxRow, final int count = mParams.layout(suggestedWords, fromIndex, maxWidth, minWidth, maxRow,
mPaneView.newLabelPaint(null /* key */), mResources); mPaneView.newLabelPaint(null /* key */), getMContext());
mFromIndex = fromIndex; mFromIndex = fromIndex;
mToIndex = fromIndex + count; mToIndex = fromIndex + count;
mSuggestedWords = suggestedWords; mSuggestedWords = suggestedWords;
@ -194,7 +195,7 @@ public final class MoreSuggestions extends Keyboard {
} }
@Override @Override
public MoreSuggestions build() { @NonNull public MoreSuggestions build() {
final MoreSuggestionsParam params = mParams; final MoreSuggestionsParam params = mParams;
for (int index = mFromIndex; index < mToIndex; index++) { for (int index = mFromIndex; index < mToIndex; index++) {
final int x = params.getX(index); final int x = params.getX(index);

View file

@ -67,8 +67,8 @@ import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.PopupMenu; import androidx.appcompat.widget.PopupMenu;
import androidx.core.view.ViewCompat;
public final class SuggestionStripView extends RelativeLayout implements OnClickListener, public final class SuggestionStripView extends RelativeLayout implements OnClickListener,
OnLongClickListener { OnLongClickListener {
@ -76,7 +76,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
void pickSuggestionManually(SuggestedWordInfo word); void pickSuggestionManually(SuggestedWordInfo word);
void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat); void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat);
void removeSuggestion(final String word); void removeSuggestion(final String word);
CharSequence getSelection();
} }
public static boolean DEBUG_SUGGESTIONS; public static boolean DEBUG_SUGGESTIONS;
@ -124,8 +123,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
} }
public void setLayoutDirection(final int layoutDirection) { public void setLayoutDirection(final int layoutDirection) {
ViewCompat.setLayoutDirection(mSuggestionStripView, layoutDirection); mSuggestionStripView.setLayoutDirection(layoutDirection);
ViewCompat.setLayoutDirection(mSuggestionsStrip, layoutDirection); mSuggestionsStrip.setLayoutDirection(layoutDirection);
} }
public void showSuggestionsStrip() { public void showSuggestionsStrip() {
@ -141,6 +140,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
this(context, attrs, R.attr.suggestionStripViewStyle); this(context, attrs, R.attr.suggestionStripViewStyle);
} }
@SuppressLint("InflateParams") // does not seem suitable here
public SuggestionStripView(final Context context, final AttributeSet attrs, final int defStyle) { public SuggestionStripView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
final Colors colors = Settings.getInstance().getCurrent().mColors; final Colors colors = Settings.getInstance().getCurrent().mColors;
@ -183,6 +183,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
R.dimen.config_more_suggestions_modal_tolerance); R.dimen.config_more_suggestions_modal_tolerance);
mMoreSuggestionsSlidingDetector = new GestureDetector(context, mMoreSuggestionsSlidingListener); mMoreSuggestionsSlidingDetector = new GestureDetector(context, mMoreSuggestionsSlidingListener);
@SuppressLint("CustomViewStyleable")
final TypedArray keyboardAttr = context.obtainStyledAttributes(attrs, R.styleable.Keyboard, defStyle, R.style.SuggestionStripView); final TypedArray keyboardAttr = context.obtainStyledAttributes(attrs, R.styleable.Keyboard, defStyle, R.style.SuggestionStripView);
mIncognitoIcon = keyboardAttr.getDrawable(R.styleable.Keyboard_iconIncognitoKey); mIncognitoIcon = keyboardAttr.getDrawable(R.styleable.Keyboard_iconIncognitoKey);
mToolbarArrowIcon = keyboardAttr.getDrawable(R.styleable.Keyboard_iconToolbarKey); mToolbarArrowIcon = keyboardAttr.getDrawable(R.styleable.Keyboard_iconToolbarKey);
@ -262,9 +263,9 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
public void setRtl(final boolean isRtlLanguage) { public void setRtl(final boolean isRtlLanguage) {
final int layoutDirection; final int layoutDirection;
if (!Settings.getInstance().getCurrent().mVarToolbarDirection) if (!Settings.getInstance().getCurrent().mVarToolbarDirection)
layoutDirection = ViewCompat.LAYOUT_DIRECTION_LOCALE; layoutDirection = View.LAYOUT_DIRECTION_LOCALE;
else{ else{
layoutDirection = isRtlLanguage ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR; layoutDirection = isRtlLanguage ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
mRtl = isRtlLanguage ? -1 : 1; mRtl = isRtlLanguage ? -1 : 1;
} }
mStripVisibilityGroup.setLayoutDirection(layoutDirection); mStripVisibilityGroup.setLayoutDirection(layoutDirection);
@ -528,7 +529,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
private final GestureDetector.OnGestureListener mMoreSuggestionsSlidingListener = private final GestureDetector.OnGestureListener mMoreSuggestionsSlidingListener =
new GestureDetector.SimpleOnGestureListener() { new GestureDetector.SimpleOnGestureListener() {
@Override @Override
public boolean onScroll(MotionEvent down, MotionEvent me, float deltaX, float deltaY) { public boolean onScroll(@Nullable MotionEvent down, @NonNull MotionEvent me, float deltaX, float deltaY) {
if (down == null) return false;
final float dy = me.getY() - down.getY(); final float dy = me.getY() - down.getY();
if (mToolbarContainer.getVisibility() != VISIBLE && deltaY > 0 && dy < 0) { if (mToolbarContainer.getVisibility() != VISIBLE && deltaY > 0 && dy < 0) {
return showMoreSuggestions(); return showMoreSuggestions();
@ -637,7 +639,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(KeyCode.NOT_SPECIFIED, this); AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(KeyCode.NOT_SPECIFIED, this);
final Object tag = view.getTag(); final Object tag = view.getTag();
if (tag instanceof ToolbarKey) { if (tag instanceof ToolbarKey) {
final Integer code = getCodeForToolbarKey((ToolbarKey) tag); final int code = getCodeForToolbarKey((ToolbarKey) tag);
if (code != KeyCode.UNSPECIFIED) { if (code != KeyCode.UNSPECIFIED) {
Log.d(TAG, "click toolbar key "+tag); Log.d(TAG, "click toolbar key "+tag);
mListener.onCodeInput(code, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE, false); mListener.onCodeInput(code, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE, false);

View file

@ -18,7 +18,6 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.RawKeyboardParser
import helium314.keyboard.keyboard.internal.keyboard_parser.addLocaleKeyTextsToParams import helium314.keyboard.keyboard.internal.keyboard_parser.addLocaleKeyTextsToParams
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.common.FileUtils import helium314.keyboard.latin.common.FileUtils
import helium314.keyboard.latin.settings.Settings
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.math.BigInteger import java.math.BigInteger
@ -80,13 +79,13 @@ private fun checkLayout(layoutContent: String, context: Context): Boolean? {
params.mPopupKeyTypes.add(POPUP_KEYS_LAYOUT) params.mPopupKeyTypes.add(POPUP_KEYS_LAYOUT)
addLocaleKeyTextsToParams(context, params, POPUP_KEYS_NORMAL) addLocaleKeyTextsToParams(context, params, POPUP_KEYS_NORMAL)
try { try {
val keys = RawKeyboardParser.parseJsonString(layoutContent).map { it.mapNotNull { it.compute(params)?.toKeyParams(params) } } val keys = RawKeyboardParser.parseJsonString(layoutContent).map { row -> row.mapNotNull { it.compute(params)?.toKeyParams(params) } }
if (!checkKeys(keys)) if (!checkKeys(keys))
return null return null
return true return true
} catch (e: Exception) { Log.w(TAG, "error parsing custom json layout", e) } } catch (e: Exception) { Log.w(TAG, "error parsing custom json layout", e) }
try { try {
val keys = RawKeyboardParser.parseSimpleString(layoutContent).map { it.map { it.toKeyParams(params) } } val keys = RawKeyboardParser.parseSimpleString(layoutContent).map { row -> row.map { it.toKeyParams(params) } }
if (!checkKeys(keys)) if (!checkKeys(keys))
return null return null
return false return false
@ -94,7 +93,7 @@ private fun checkLayout(layoutContent: String, context: Context): Boolean? {
if (layoutContent.startsWith("[")) { if (layoutContent.startsWith("[")) {
// layout can't be loaded, assume it's json -> load json layout again because the error message shown to the user is from the most recent error // layout can't be loaded, assume it's json -> load json layout again because the error message shown to the user is from the most recent error
try { try {
RawKeyboardParser.parseJsonString(layoutContent).map { it.mapNotNull { it.compute(params)?.toKeyParams(params) } } RawKeyboardParser.parseJsonString(layoutContent).map { row -> row.mapNotNull { it.compute(params)?.toKeyParams(params) } }
} catch (e: Exception) { Log.w(TAG, "error parsing custom json layout", e) } } catch (e: Exception) { Log.w(TAG, "error parsing custom json layout", e) }
} }
return null return null
@ -109,19 +108,19 @@ private fun checkKeys(keys: List<List<Key.KeyParams>>): Boolean {
Log.w(TAG, "too many rows") Log.w(TAG, "too many rows")
return false return false
} }
if (keys.any { it.size > 20 }) { if (keys.any { row -> row.size > 20 }) {
Log.w(TAG, "too many keys in one row") Log.w(TAG, "too many keys in one row")
return false return false
} }
if (keys.any { it.any { ((it.mLabel?.length ?: 0) > 6) } }) { if (keys.any { row -> row.any { ((it.mLabel?.length ?: 0) > 6) } }) {
Log.w(TAG, "too long text on key") Log.w(TAG, "too long text on key")
return false return false
} }
if (keys.any { it.any { (it.mPopupKeys?.size ?: 0) > 20 } }) { if (keys.any { row -> row.any { (it.mPopupKeys?.size ?: 0) > 20 } }) {
Log.w(TAG, "too many popup keys on a key") Log.w(TAG, "too many popup keys on a key")
return false return false
} }
if (keys.any { it.any { it.mPopupKeys?.any { (it.mLabel?.length ?: 0) > 10 } == true } }) { if (keys.any { row -> row.any { it.mPopupKeys?.any { popupKey -> (popupKey.mLabel?.length ?: 0) > 10 } == true } }) {
Log.w(TAG, "too long text on popup key") Log.w(TAG, "too long text on popup key")
return false return false
} }

View file

@ -29,7 +29,7 @@ public class RecapitalizeStatus {
CAPS_MODE_ALL_UPPER CAPS_MODE_ALL_UPPER
}; };
private static final int getStringMode(final String string, final int[] sortedSeparators) { private static int getStringMode(final String string, final int[] sortedSeparators) {
if (StringUtils.isIdenticalAfterUpcase(string)) { if (StringUtils.isIdenticalAfterUpcase(string)) {
return CAPS_MODE_ALL_UPPER; return CAPS_MODE_ALL_UPPER;
} else if (StringUtils.isIdenticalAfterDowncase(string)) { } else if (StringUtils.isIdenticalAfterDowncase(string)) {
@ -42,14 +42,14 @@ public class RecapitalizeStatus {
} }
public static String modeToString(final int recapitalizeMode) { public static String modeToString(final int recapitalizeMode) {
switch (recapitalizeMode) { return switch (recapitalizeMode) {
case NOT_A_RECAPITALIZE_MODE: return "undefined"; case NOT_A_RECAPITALIZE_MODE -> "undefined";
case CAPS_MODE_ORIGINAL_MIXED_CASE: return "mixedCase"; case CAPS_MODE_ORIGINAL_MIXED_CASE -> "mixedCase";
case CAPS_MODE_ALL_LOWER: return "allLower"; case CAPS_MODE_ALL_LOWER -> "allLower";
case CAPS_MODE_FIRST_WORD_UPPER: return "firstWordUpper"; case CAPS_MODE_FIRST_WORD_UPPER -> "firstWordUpper";
case CAPS_MODE_ALL_UPPER: return "allUpper"; case CAPS_MODE_ALL_UPPER -> "allUpper";
default: return "unknown<" + recapitalizeMode + ">"; default -> "unknown<" + recapitalizeMode + ">";
} };
} }
/** /**
@ -145,21 +145,10 @@ public class RecapitalizeStatus {
} }
++count; ++count;
switch (ROTATION_STYLE[mRotationStyleCurrentIndex]) { switch (ROTATION_STYLE[mRotationStyleCurrentIndex]) {
case CAPS_MODE_ORIGINAL_MIXED_CASE: case CAPS_MODE_ALL_LOWER -> mStringAfter = mStringBefore.toLowerCase(mLocale);
mStringAfter = mStringBefore; case CAPS_MODE_FIRST_WORD_UPPER -> mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSortedSeparators, mLocale);
break; case CAPS_MODE_ALL_UPPER -> mStringAfter = mStringBefore.toUpperCase(mLocale);
case CAPS_MODE_ALL_LOWER: default -> mStringAfter = mStringBefore;
mStringAfter = mStringBefore.toLowerCase(mLocale);
break;
case CAPS_MODE_FIRST_WORD_UPPER:
mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSortedSeparators,
mLocale);
break;
case CAPS_MODE_ALL_UPPER:
mStringAfter = mStringBefore.toUpperCase(mLocale);
break;
default:
mStringAfter = mStringBefore;
} }
} while (mStringAfter.equals(oldResult) && count < ROTATION_STYLE.length + 1); } while (mStringAfter.equals(oldResult) && count < ROTATION_STYLE.length + 1);
mCursorEndAfter = mCursorStartAfter + mStringAfter.length(); mCursorEndAfter = mCursorStartAfter + mStringAfter.length();

View file

@ -2,7 +2,6 @@ package helium314.keyboard
import helium314.keyboard.keyboard.internal.KeySpecParser import helium314.keyboard.keyboard.internal.KeySpecParser
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
import helium314.keyboard.latin.common.Constants
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test

View file

@ -867,7 +867,7 @@ private val ic = object : InputConnection {
// update selection // update selection
selectionStart -= beforeLength selectionStart -= beforeLength
selectionEnd -= beforeLength selectionEnd -= beforeLength
return true; return true
} }
override fun sendKeyEvent(p0: KeyEvent): Boolean { override fun sendKeyEvent(p0: KeyEvent): Boolean {
if (p0.action != KeyEvent.ACTION_DOWN) return true // only change the text on key down, like RichInputConnection does if (p0.action != KeyEvent.ACTION_DOWN) return true // only change the text on key down, like RichInputConnection does
@ -908,7 +908,7 @@ private val ic = object : InputConnection {
override fun clearMetaKeyStates(p0: Int): Boolean = TODO("Not yet implemented") override fun clearMetaKeyStates(p0: Int): Boolean = TODO("Not yet implemented")
override fun reportFullscreenMode(p0: Boolean): Boolean = TODO("Not yet implemented") override fun reportFullscreenMode(p0: Boolean): Boolean = TODO("Not yet implemented")
override fun performPrivateCommand(p0: String?, p1: Bundle?): Boolean = TODO("Not yet implemented") override fun performPrivateCommand(p0: String?, p1: Bundle?): Boolean = TODO("Not yet implemented")
override fun getHandler(): Handler? = TODO("Not yet implemented") override fun getHandler(): Handler = TODO("Not yet implemented")
override fun closeConnection() = TODO("Not yet implemented") override fun closeConnection() = TODO("Not yet implemented")
override fun commitContent(p0: InputContentInfo, p1: Int, p2: Bundle?): Boolean = TODO("Not yet implemented") override fun commitContent(p0: InputContentInfo, p1: Int, p2: Bundle?): Boolean = TODO("Not yet implemented")
} }

View file

@ -25,6 +25,7 @@ import org.robolectric.annotation.Implements
import org.robolectric.shadows.ShadowLog import org.robolectric.shadows.ShadowLog
import java.util.* import java.util.*
@Suppress("NonAsciiCharacters")
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
@Config(shadows = [ @Config(shadows = [
ShadowLocaleManagerCompat::class, ShadowLocaleManagerCompat::class,

View file

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.9.23' ext.kotlin_version = '1.9.24'
repositories { repositories {
mavenCentral() mavenCentral()
google() google()
@ -17,7 +17,7 @@ buildscript {
} }
plugins { plugins {
id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.23' apply false id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version"
} }
allprojects { allprojects {