32 Commits
Author SHA1 Message Date
emil 32ae47e349 Fix alt+backspace deleting lines of text, add Greek question mark under Alt+X in Greek layout, move Arabic diacritics to shifted symbols, fix button being displayed in all caps 2024-11-13 17:01:31 +01:00
emil 185d518faa Bring back automatic cycling 2024-11-09 00:03:41 +01:00
emil 0628a4bdb9 Linting 2024-11-08 23:55:46 +01:00
emil dbb3ddb7ff Some additional input checks 2024-11-08 23:48:13 +01:00
emil 35693a3981 Add additional method for cycling symbols using consecutive presses 2024-11-08 23:44:13 +01:00
emil 8850c99b93 Simplify key event handling 2024-11-08 21:53:55 +01:00
emil b4a0e12257 UI style revamp 2024-11-08 21:30:03 +01:00
emil 913d4aad40 Make the space key definable in keymaps 2024-11-08 19:37:06 +01:00
emil 09238d8056 Small misc. changes, renames, etc. 2024-11-08 18:00:59 +01:00
emil 001ce70392 Strict inspection warnings fixed, slight restructurings 2024-11-05 23:36:09 +01:00
emil 0445279671 Minor keymap tweaks 2024-11-05 20:58:28 +01:00
emil adc60420b2 Change package name, yet again 2024-11-05 18:28:56 +01:00
emil 68c8ed9a54 Update lint profile 2024-11-05 18:00:01 +01:00
emil 3462a5eb9f Very strict linter profile 2024-11-05 15:45:09 +01:00
emil 970f65f245 Inspection error fixes 2024-11-05 11:31:05 +01:00
emil fdbf73720b Misc. 2024-11-04 23:44:21 +01:00
emil 792216e22d Update compile and targetSdk 2024-11-04 20:18:56 +01:00
emil e430bbfeac Misc. changes, arabic fixes 2024-11-04 19:22:04 +01:00
emil b441d822d2 Change package name, fix drawable bugs 2024-11-04 16:45:21 +01:00
emil c29fcc4b5f Arabic revamp 2024-11-03 23:22:23 +01:00
emil 361de2a76c Miscellaneous changes 2024-11-03 20:17:41 +01:00
emil 5f1ee64952 Clipboard managment pretty much finished 2024-11-03 18:44:31 +01:00
emil ff9d115306 New icon, preliminary clipboard functionality 2024-11-01 17:15:56 +01:00
emil ec3e21d8cf Interface code improvements 2024-11-01 00:57:27 +01:00
emil 004dfdbe8f Miscellaneous changes, more languages 2024-10-31 19:06:36 +01:00
emil d5e7102de3 Miscellaneous changes, more languages 2024-10-31 19:04:39 +01:00
emil 11fd71508b Greek polytonic diacritics 2024-10-23 23:46:27 +02:00
emil 335cffe433 Bugfixes and possibility to have multiple-character symbols. 2024-10-23 23:24:18 +02:00
emil 640ad71198 A rather working version 2024-10-23 22:43:31 +02:00
emil 7108e2beb9 Auto-capitalization on newline 2024-10-23 20:31:36 +02:00
emil 989752669a Support for down to Android 1.5 (Cupcake) 2024-10-23 20:24:06 +02:00
emil 681e2024de Fix auto-capitalization so that it works rather flawlessly 2024-10-22 19:49:22 +02:00
46 changed files with 3673 additions and 1298 deletions
+967
View File
@@ -0,0 +1,967 @@
<profile version="1.0">
<option name="myName" value="Very strict" />
<inspection_tool class="AbsoluteAlignmentInUserInterface" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AbstractClassExtendsConcreteClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AbstractClassNeverImplemented" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AbstractClassWithOnlyOneDirectInheritor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AbstractClassWithoutAbstractMethods" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AbstractMethodCallInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AbstractMethodOverridesAbstractMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AbstractMethodOverridesConcreteMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AbstractMethodWithMissingImplementations" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AccessToNonThreadSafeStaticFieldFromInstance" enabled="true" level="WARNING" enabled_by_default="true">
<option name="nonThreadSafeClasses">
<value />
</option>
<option name="nonThreadSafeTypes" value="" />
</inspection_tool>
<inspection_tool class="AccessToStaticFieldLockedOnInstance" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AddConversionCallMigration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AmbiguousExpressionInWhenBranchMigration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AmbiguousFieldAccess" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AmbiguousMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintAppCompatMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintAppLinksAutoVerify" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintBackButton" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintConvertToWebp" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintDuplicateStrings" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintEasterEgg" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintExpensiveAssertion" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintIconExpectedSize" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintImplicitSamInstance" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintKotlinPropertyAccess" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintKotlincFE10" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintLambdaLast" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintLogConditional" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintMangledCRLF" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintNegativeMargin" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintNewerVersionAvailable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintNoHardKeywords" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintNoOp" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintPermissionNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintRegistered" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintSelectableText" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintStopShip" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintStringFormatTrivial" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintSyntheticAccessor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintTypographyQuotes" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintUnsafeImplicitIntentLaunch" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintUnsupportedChromeOsHardware" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintUnusedIds" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintValidActionsXml" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintWrongThreadInterprocedural" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AnnotationClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AnonymousClassComplexity" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="3" />
</inspection_tool>
<inspection_tool class="AnonymousClassMethodCount" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="1" />
</inspection_tool>
<inspection_tool class="AnonymousClassVariableHidesContainingMethodVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AnonymousInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AnonymousInnerClassMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ArrayEquality" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ArrayLengthInLoopCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssertEqualsCalledOnArray" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssertEqualsMayBeAssertSame" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssertMessageNotString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssertStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssertWithoutMessage" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentOrReturnOfFieldWithMutableType" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_checkForeachParameters" value="true" />
</inspection_tool>
<inspection_tool class="AssignmentToLambdaParameter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentToMethodParameter" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreTransformationOfOriginalParameter" value="false" />
</inspection_tool>
<inspection_tool class="AssignmentToNull" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentToStaticFieldFromInstanceMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentToSuperclassField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AwaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AwaitWithoutCorrespondingSignal" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BadExceptionCaught" enabled="true" level="WARNING" enabled_by_default="true">
<option name="exceptionsString" value="" />
<option name="exceptions">
<value />
</option>
</inspection_tool>
<inspection_tool class="BadExceptionDeclared" enabled="true" level="WARNING" enabled_by_default="true">
<option name="exceptionsString" value="" />
<option name="exceptions">
<value />
</option>
<option name="ignoreTestCases" value="false" />
<option name="ignoreLibraryOverrides" value="false" />
</inspection_tool>
<inspection_tool class="BadExceptionThrown" enabled="true" level="WARNING" enabled_by_default="true">
<option name="exceptionsString" value="" />
<option name="exceptions">
<value />
</option>
</inspection_tool>
<inspection_tool class="BadOddness" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BigDecimalEquals" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BlockMarkerComments" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BooleanMethodNameMustStartWithQuestion" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreBooleanMethods" value="false" />
<option name="ignoreInAnnotationInterface" value="true" />
<option name="onlyWarnOnBaseMethods" value="true" />
<option name="questionString" value="are,can,check,contains,could,endsWith,equals,has,is,matches,must,shall,should,startsWith,was,were,will,would" />
</inspection_tool>
<inspection_tool class="BooleanParameter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BoundedWildcard" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BreakStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BreakStatementWithLabel" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BulkFileAttributesRead" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CallToNativeMethodWhileLocked" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CallToSimpleGetterInClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreGetterCallsOnOtherObjects" value="false" />
<option name="onlyReportPrivateGetter" value="false" />
</inspection_tool>
<inspection_tool class="CallToSimpleSetterInClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreSetterCallsOnOtherObjects" value="false" />
<option name="onlyReportPrivateSetter" value="false" />
</inspection_tool>
<inspection_tool class="CallToStringConcatCanBeReplacedByOperator" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CallingMethodShouldBeRequiresBlockingContext" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="CancellationCheckInLoops" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CastConflictsWithInstanceof" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CastDueToProgressionResolutionChangeMigration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CastThatLosesPrecision" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreIntegerCharCasts" value="false" />
<option name="ignoreOverflowingByteCasts" value="false" />
</inspection_tool>
<inspection_tool class="CastToIncompatibleInterface" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ChainedEquality" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ChannelResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="insideTryAllowed" value="false" />
</inspection_tool>
<inspection_tool class="CharUsedInArithmeticContext" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CharacterComparison" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CheckForOutOfMemoryOnLargeArrayAllocation" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="64" />
</inspection_tool>
<inspection_tool class="CheckedExceptionClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClangTidy" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClashingGetters" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassComplexity" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="80" />
</inspection_tool>
<inspection_tool class="ClassCoupling" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_includeJavaClasses" value="false" />
<option name="m_includeLibraryClasses" value="false" />
<option name="m_limit" value="15" />
</inspection_tool>
<inspection_tool class="ClassInheritanceDepth" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="2" />
</inspection_tool>
<inspection_tool class="ClassInitializer" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassLoaderInstantiation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassNameDiffersFromFileName" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassNamePrefixedWithPackageName" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassNameSameAsAncestorName" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassNestingDepth" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="1" />
</inspection_tool>
<inspection_tool class="ClassNewInstance" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassOnlyUsedInOneModule" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassOnlyUsedInOnePackage" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassReferencesSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassWithMultipleLoggers" enabled="true" level="WARNING" enabled_by_default="true">
<option name="loggerNamesString" value="java.util.logging.Logger,org.slf4j.Logger,org.apache.commons.logging.Log,org.apache.log4j.Logger,org.apache.logging.log4j.Logger" />
</inspection_tool>
<inspection_tool class="ClassWithOnlyPrivateConstructors" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassWithTooManyDependencies" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="10" />
</inspection_tool>
<inspection_tool class="ClassWithTooManyDependents" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="10" />
</inspection_tool>
<inspection_tool class="ClassWithTooManyTransitiveDependencies" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="35" />
</inspection_tool>
<inspection_tool class="ClassWithTooManyTransitiveDependents" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="35" />
</inspection_tool>
<inspection_tool class="CloneCallsConstructors" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CloneInNonCloneableClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CloneReturnsClassType" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CollectionsFieldAccessReplaceableByMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CollectionsMustHaveInitialCapacity" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ComparableImplementedButEqualsNotOverridden" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ComparatorNotSerializable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CompareToUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ComparisonOfShortAndChar" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConditionSignal" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConfusingFloatingPointLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConfusingOctalEscape" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConnectionResource" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstantAssertArgument" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstantAssertCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstantDeclaredInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstantDeclaredInInterface" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstantMathCall" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstantValueVariableUse" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstructorCount" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreDeprecatedConstructors" value="false" />
<option name="m_limit" value="5" />
</inspection_tool>
<inspection_tool class="ContinueStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ContinueStatementWithLabel" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConvertJavadoc" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConvertOldAnnotations" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CovariantEquals" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CustomClassloader" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CustomRegExpInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CustomSecurityManager" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CyclicClassDependency" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CyclicPackageDependency" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CyclomaticComplexity" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="10" />
</inspection_tool>
<inspection_tool class="DateToString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DeclaringClassMigration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DeconstructionCanBeUsed" enabled="true" level="INFORMATION" enabled_by_default="true" />
<inspection_tool class="DefaultNotLastCaseInSwitch" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="Destructure" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="DisjointPackage" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DollarSignInName" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DoubleLiteralMayBeFloatLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DriverManagerGetConnection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DuplicateStringLiteralInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="MIN_STRING_LENGTH" value="5" />
<option name="IGNORE_PROPERTY_KEYS" value="false" />
</inspection_tool>
<inspection_tool class="DynamicRegexReplaceableByCompiledPattern" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EmptyClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignorableAnnotations">
<value />
</option>
<option name="ignoreClassWithParameterization" value="false" />
<option name="ignoreThrowables" value="true" />
<option name="commentsAreContent" value="true" />
</inspection_tool>
<inspection_tool class="EmptyDirectory" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EnumClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EnumerationCanBeIteration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EqualsAndHashcode" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EqualsCalledOnEnumConstant" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EqualsUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ErrorRethrown" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExceptionFromCatchWhichDoesntWrap" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreGetMessage" value="false" />
<option name="ignoreCantWrap" value="false" />
</inspection_tool>
<inspection_tool class="ExceptionNameDoesntEndWithException" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExceptionPackage" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExpectedExceptionNeverThrown" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExpectedExceptionNeverThrownTestNG" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExtendsConcreteCollection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExtendsThread" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExtendsThrowable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExtendsUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExtensionClassShouldBeFinalAndNonPublic" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExternalizableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FallthruInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FeatureEnvy" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreTestCases" value="false" />
</inspection_tool>
<inspection_tool class="FieldAccessNotGuarded" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FieldAccessedSynchronizedAndUnsynchronized" enabled="true" level="WARNING" enabled_by_default="true">
<option name="countGettersAndSetters" value="false" />
</inspection_tool>
<inspection_tool class="FieldCount" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_countConstantFields" value="false" />
<option name="m_considerStaticFinalFieldsConstant" value="false" />
<option name="myCountEnumConstants" value="false" />
<option name="m_limit" value="10" />
</inspection_tool>
<inspection_tool class="FieldHasSetterButNoGetter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FieldHidesSuperclassField" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreInvisibleFields" value="true" />
</inspection_tool>
<inspection_tool class="FieldMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FieldNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FieldNotUsedInToString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="Finalize" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreTrivialFinalizers" value="true" />
</inspection_tool>
<inspection_tool class="FloatingPointEquality" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ForLoopWithMissingComponent" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreCollectionLoops" value="false" />
</inspection_tool>
<inspection_tool class="ForeachStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FromClosedRangeMigration" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="GrStringStyleViolation" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="GradleKotlinxCoroutinesDeprecation" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="GroovyAssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyAssignmentToMethodParameter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyBreak" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyBusyWait" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyConditional" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyConstantNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[A-Z\d]*" />
<option name="m_minLength" value="4" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="GroovyContinue" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyContinueOrBreakFromFinallyBlock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyDoubleCheckedLocking" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreOnVolatileVariables" value="false" />
</inspection_tool>
<inspection_tool class="GroovyEmptyCatchBlock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyEmptyFinallyBlock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyEmptySyncBlock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyEmptyTryBlock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyIfStatementWithTooManyBranches" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="3" />
</inspection_tool>
<inspection_tool class="GroovyInstanceMethodNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="4" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="GroovyInstanceVariableNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="m_[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="1" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="GroovyListGetCanBeKeyedAccess" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyListSetCanBeKeyedAccess" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyLocalVariableNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="4" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="GroovyLoopStatementThatDoesntLoop" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyMapGetCanBeKeyedAccess" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyMapPutCanBeKeyedAccess" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyMethodParameterCount" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="5" />
</inspection_tool>
<inspection_tool class="GroovyMethodWithMoreThanThreeNegations" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyMultipleReturnPointsPerMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="1" />
</inspection_tool>
<inspection_tool class="GroovyNegatedConditional" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyNegatedIf" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyNestedAssignment" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyNestedConditional" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyNestedSwitch" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyNestedSynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyNonShortCircuitBoolean" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyNotifyWhileNotSynchronized" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyOctalInteger" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyOverlyComplexArithmeticExpression" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="3" />
</inspection_tool>
<inspection_tool class="GroovyOverlyComplexBooleanExpression" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="3" />
</inspection_tool>
<inspection_tool class="GroovyOverlyComplexMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="10" />
</inspection_tool>
<inspection_tool class="GroovyOverlyLongMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="30" />
</inspection_tool>
<inspection_tool class="GroovyOverlyNestedMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="5" />
</inspection_tool>
<inspection_tool class="GroovyParameterNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="4" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="GroovyPointlessArithmetic" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyPublicFieldAccessedInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyRangeTypeCheck" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyResultOfAssignmentUsed" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyResultOfIncrementOrDecrementUsed" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyReturnFromClosureCanBeImplicit" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyReturnFromFinallyBlock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyStaticMethodNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="4" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="GroovyStaticVariableNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="s_[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="4" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="GroovySwitchStatementWithNoDefault" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovySynchronizationOnThis" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovySynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovySystemRunFinalizersOnExit" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyThreadStopSuspendResume" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyThrowFromFinallyBlock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyUnconditionalWait" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyUntypedAccess" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyVariableCanBeFinal" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyWaitCallNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyWaitWhileNotSynchronized" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="GroovyWhileLoopSpinsOnField" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreNonEmtpyLoops" value="false" />
</inspection_tool>
<inspection_tool class="Guava" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="HardCodedStringLiteral" enabled="true" level="WARNING" enabled_by_default="false">
<scope name="Project Source Files" level="WARNING" enabled="true">
<option name="ignoreForAssertStatements" value="true" />
<option name="ignoreForExceptionConstructors" value="true" />
<option name="ignoreForSpecifiedExceptionConstructors" value="" />
<option name="ignoreForJUnitAsserts" value="true" />
<option name="ignoreForClassReferences" value="true" />
<option name="ignoreForPropertyKeyReferences" value="true" />
<option name="ignoreForNonAlpha" value="true" />
<option name="ignoreAssignedToConstants" value="false" />
<option name="ignoreToString" value="false" />
<option name="nonNlsCommentPattern" value="NON-NLS" />
</scope>
<option name="ignoreForAssertStatements" value="true" />
<option name="ignoreForExceptionConstructors" value="true" />
<option name="ignoreForSpecifiedExceptionConstructors" value="" />
<option name="ignoreForJUnitAsserts" value="true" />
<option name="ignoreForClassReferences" value="true" />
<option name="ignoreForPropertyKeyReferences" value="true" />
<option name="ignoreForNonAlpha" value="true" />
<option name="ignoreAssignedToConstants" value="false" />
<option name="ignoreToString" value="false" />
<option name="nonNlsCommentPattern" value="NON-NLS" />
</inspection_tool>
<inspection_tool class="HardcodedFileSeparators" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_recognizeExampleMediaType" value="false" />
</inspection_tool>
<inspection_tool class="HardcodedLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="HashCodeUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="HibernateResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="insideTryAllowed" value="false" />
</inspection_tool>
<inspection_tool class="HtmlNonExistentInternetResource" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="HtmlPresentationalElement" enabled="true" level="INFORMATION" enabled_by_default="true" />
<inspection_tool class="HtmlRequiredSummaryAttribute" enabled="true" level="INFORMATION" enabled_by_default="true" />
<inspection_tool class="HtmlRequiredTitleAttribute" enabled="true" level="INFORMATION" enabled_by_default="true" />
<inspection_tool class="HtmlTagCanBeJavadocTag" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IOResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredTypesString" value="java.io.ByteArrayOutputStream,java.io.ByteArrayInputStream,java.io.StringBufferInputStream,java.io.CharArrayWriter,java.io.CharArrayReader,java.io.StringWriter,java.io.StringReader" />
<option name="insideTryAllowed" value="false" />
</inspection_tool>
<inspection_tool class="IfStatementWithTooManyBranches" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="3" />
</inspection_tool>
<inspection_tool class="IgnoredJUnitTest" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IllegalDependencyOnInternalPackage" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ImplicitDefaultCharsetUsage" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IncompleteDestructuring" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InconsistentLanguageLevel" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IncorrectProcessCanceledExceptionHandling" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="IncrementDecrementUsedAsExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InlineClassDeprecatedMigration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InnerClassOnInterface" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreInnerInterfaces" value="false" />
</inspection_tool>
<inspection_tool class="InnerClassReferencedViaSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InnerClassVariableHidesOuterClassVariable" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreInvisibleFields" value="true" />
</inspection_tool>
<inspection_tool class="InstanceGuardedByStatic" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InstanceVariableUninitializedUse" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignorePrimitives" value="false" />
<option name="annotationNamesString" value="" />
</inspection_tool>
<inspection_tool class="InstanceofCatchParameter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InstanceofChain" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreInstanceofOnLibraryClasses" value="false" />
</inspection_tool>
<inspection_tool class="InstanceofIncompatibleInterface" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InstanceofThis" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IntLiteralMayBeLongLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InterfaceMayBeAnnotatedFunctional" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InterfaceNeverImplemented" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreInterfacesThatOnlyDeclareConstants" value="false" />
</inspection_tool>
<inspection_tool class="InterfaceWithOnlyOneDirectInheritor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IteratorNextDoesNotThrowNoSuchElementException" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="JDBCExecuteWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="JDBCPrepareStatementWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="JDBCResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="insideTryAllowed" value="false" />
</inspection_tool>
<inspection_tool class="JNDIResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="insideTryAllowed" value="false" />
</inspection_tool>
<inspection_tool class="JUnit5Converter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="JUnitTestNG" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="JavaLangImport" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="JavadocHtmlLint" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="KDocMissingDocumentation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="KeySetIterationMayUseEntrySet" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="KotlinLoggerInitializedWithForeignClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LabeledStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LambdaParameterHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LambdaParameterNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LambdaUnfriendlyMethodOverload" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LengthOneStringInIndexOf" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LimitedScopeInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ListenerMayUseAdapter" enabled="true" level="WARNING" enabled_by_default="true">
<option name="checkForEmptyMethods" value="true" />
</inspection_tool>
<inspection_tool class="LiteralAsArgToStringEquals" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LoadLibraryWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LocalVariableHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreInvisibleFields" value="true" />
<option name="m_ignoreStaticMethods" value="true" />
</inspection_tool>
<inspection_tool class="LocalVariableNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreForLoopParameters" value="false" />
<option name="m_ignoreCatchParameters" value="false" />
<option name="m_regex" value="[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="1" />
<option name="m_maxLength" value="20" />
</inspection_tool>
<inspection_tool class="LogStatementGuardedByLogCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LoggerInitializedWithForeignClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
</inspection_tool>
<inspection_tool class="LoggingConditionDisagreesWithLogLevelStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LongLine" enabled="true" level="WEAK WARNING" enabled_by_default="true" editorAttributes="INFO_ATTRIBUTES" />
<inspection_tool class="LoopWithImplicitTerminationCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MagicCharacter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MagicNumber" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MapReplaceableByEnumMap" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MarkerInterface" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodCallInLoopCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodCount" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="20" />
<option name="ignoreGettersAndSetters" value="false" />
<option name="ignoreOverridingMethods" value="false" />
</inspection_tool>
<inspection_tool class="MethodCoupling" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_includeJavaClasses" value="false" />
<option name="m_includeLibraryClasses" value="false" />
<option name="m_limit" value="10" />
</inspection_tool>
<inspection_tool class="MethodMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_onlyPrivateOrFinal" value="false" />
<option name="m_ignoreEmptyMethods" value="true" />
</inspection_tool>
<inspection_tool class="MethodMayBeSynchronized" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodNameSameAsParentName" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodOnlyUsedFromInnerClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreMethodsAccessedFromAnonymousClass" value="false" />
<option name="ignoreStaticMethodsFromNonStaticInnerClass" value="false" />
<option name="onlyReportStaticMethods" value="false" />
</inspection_tool>
<inspection_tool class="MethodOverloadsParentMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodOverridesInaccessibleMethodOfSuper" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodOverridesStaticMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodReturnAlwaysConstant" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodWithMultipleLoops" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MigrateAssertToMatcherAssert" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MisorderedAssertEqualsArguments" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="Misra" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MissingDeprecatedAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MisspelledEquals" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MisspelledMethodName" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ModuleWithTooFewClasses" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="10" />
</inspection_tool>
<inspection_tool class="ModuleWithTooManyClasses" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="100" />
</inspection_tool>
<inspection_tool class="MultipleExceptionsDeclaredOnTestMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MultipleReturnPointsPerMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreGuardClauses" value="false" />
<option name="ignoreEqualsMethod" value="false" />
<option name="m_limit" value="1" />
</inspection_tool>
<inspection_tool class="MultipleTopLevelClassesInFile" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MultiplyOrDivideByPowerOfTwo" enabled="true" level="WARNING" enabled_by_default="true">
<option name="checkDivision" value="false" />
</inspection_tool>
<inspection_tool class="NakedNotify" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NativeMethods" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NegatedConditional" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreNegatedNullComparison" value="true" />
</inspection_tool>
<inspection_tool class="NegatedConditionalExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NegatedEqualityExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NegatedIfElse" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreNegatedNullComparison" value="true" />
<option name="m_ignoreNegatedZeroComparison" value="false" />
</inspection_tool>
<inspection_tool class="NegativelyNamedBooleanVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NestedAssignment" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NestedConditionalExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NestedSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NestedSynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NestedTryStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NestingDepth" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="5" />
</inspection_tool>
<inspection_tool class="NewExceptionWithoutArguments" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NewGroovyClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NewMethodNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NoConstructorMigration" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="NonBooleanMethodNameMayNotStartWithQuestion" enabled="true" level="WARNING" enabled_by_default="true">
<option name="questionString" value="are,can,check,contains,could,endsWith,equals,has,is,matches,must,shall,should,startsWith,was,were,will,would" />
<option name="ignoreBooleanMethods" value="false" />
<option name="onlyWarnOnBaseMethods" value="true" />
</inspection_tool>
<inspection_tool class="NonCommentSourceStatements" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="30" />
</inspection_tool>
<inspection_tool class="NonExceptionNameEndsWithException" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonExhaustiveWhenStatementMigration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonFinalClone" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonFinalFieldInImmutable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonFinalFieldOfException" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonFinalGuard" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonFinalStaticVariableUsedInClassInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonFinalUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonNullableBooleanPropertyInExternalInterface" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonProtectedConstructorInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreNonPublicClasses" value="false" />
</inspection_tool>
<inspection_tool class="NonPublicClone" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonReproducibleMathCall" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonSerializableObjectBoundToHttpSession" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonSerializableObjectPassedToObjectStream" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonSerializableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonShortCircuitBoolean" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonStaticFinalLogger" enabled="true" level="WARNING" enabled_by_default="true">
<option name="loggerClassName" value="java.util.logging.Logger,org.slf4j.Logger,org.apache.commons.logging.Log,org.apache.log4j.Logger,org.apache.logging.log4j.Logger" />
</inspection_tool>
<inspection_tool class="NonSynchronizedMethodOverridesSynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonThreadSafeLazyInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NoopMethodInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NotifyCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NotifyWithoutCorrespondingWait" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NullThrown" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NumericToString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OCDFA" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OCInconsistentNaming" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="OCUnusedIncludeDirective" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ObjectAllocationInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ObjectInstantiationInEqualsHashCode" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ObjectNotify" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ObjectToString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreRequiredObsoleteCollectionTypes" value="true" />
</inspection_tool>
<inspection_tool class="ObsoleteExperimentalCoroutines" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ObsoleteKotlinJsPackages" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="OctalAndDecimalIntegersMixed" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OnDemandImport" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OptionalContainsCollection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OverloadedMethodsWithSameNumberOfParameters" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreInconvertibleTypes" value="true" />
</inspection_tool>
<inspection_tool class="OverloadedVarargsMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OverlyComplexArithmeticExpression" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="6" />
</inspection_tool>
<inspection_tool class="OverlyComplexBooleanExpression" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="3" />
<option name="m_ignorePureConjunctionsDisjunctions" value="true" />
</inspection_tool>
<inspection_tool class="OverlyLargePrimitiveArrayInitializer" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="64" />
</inspection_tool>
<inspection_tool class="OverlyLongLambda" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OverlyStrongTypeCast" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreInMatchingInstanceof" value="false" />
</inspection_tool>
<inspection_tool class="OverridableMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OverriddenMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OverrideDeprecatedMigration" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="PackageDotHtmlMayBePackageInfo" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PackageInMultipleModules" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PackageNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[a-z]*" />
<option name="m_minLength" value="3" />
<option name="m_maxLength" value="16" />
</inspection_tool>
<inspection_tool class="PackageWithTooFewClasses" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="3" />
</inspection_tool>
<inspection_tool class="PackageWithTooManyClasses" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="50" />
</inspection_tool>
<inspection_tool class="ParameterHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreInvisibleFields" value="true" />
<option name="m_ignoreStaticMethodParametersHidingInstanceFields" value="true" />
<option name="m_ignoreForConstructors" value="false" />
<option name="m_ignoreForPropertySetters" value="false" />
<option name="m_ignoreForAbstractMethods" value="false" />
</inspection_tool>
<inspection_tool class="ParameterNameDiffersFromOverriddenParameter" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreSingleCharacterNames" value="false" />
<option name="m_ignoreOverridesOfLibraryMethods" value="false" />
</inspection_tool>
<inspection_tool class="ParameterNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="1" />
<option name="m_maxLength" value="20" />
</inspection_tool>
<inspection_tool class="ParameterTypePreventsOverriding" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ParameterizedParametersStaticCollection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ParametersPerConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ParametersPerMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="5" />
</inspection_tool>
<inspection_tool class="PluginXmlI18n" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PointlessIndexOfComparison" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PrivateMemberAccessBetweenOuterAndInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ProblematicVarargsMethodOverride" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ProblematicWhitespace" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ProhibitJvmOverloadsOnConstructorsOfAnnotationClassesMigration" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ProhibitRepeatedUseSiteTargetAnnotationsMigration" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ProhibitTypeParametersForLocalVariablesMigration" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ProhibitUseSiteTargetAnnotationsOnSuperTypesMigration" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="PropertyValueSetToItself" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ProtectedField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ProtectedInnerClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreEnums" value="false" />
<option name="ignoreInterfaces" value="false" />
</inspection_tool>
<inspection_tool class="PublicApiImplicitType" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PublicConstructorInNonPublicClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PublicFieldAccessedInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PublicInnerClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreEnums" value="false" />
<option name="ignoreInterfaces" value="false" />
</inspection_tool>
<inspection_tool class="PublicStaticArrayField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PublicStaticCollectionField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="QuestionableName" enabled="true" level="WARNING" enabled_by_default="true">
<option name="nameString" value="aa,abc,bad,bar,bar2,baz,baz1,baz2,baz3,bb,blah,bogus,bool,cc,dd,defau1t,dummy,dummy2,ee,fa1se,ff,foo,foo1,foo2,foo3,foobar,four,fred,fred1,fred2,gg,hh,hello,hello1,hello2,hello3,ii,nu11,one,silly,silly2,string,two,that,then,three,whi1e,var" />
</inspection_tool>
<inspection_tool class="RandomDoubleForRandomInteger" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ReadObjectAndWriteObjectPrivate" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ReadObjectInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ReadResolveAndWriteReplaceProtected" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RecordStoreResource" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RedundantFieldInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RedundantImplements" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreSerializable" value="false" />
<option name="ignoreCloneable" value="false" />
</inspection_tool>
<inspection_tool class="RedundantInnerClassModifier" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RedundantLabelMigration" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="RedundantNotNullExtensionReceiverOfInline" enabled="true" level="INFORMATION" enabled_by_default="true" />
<inspection_tool class="RedundantValueArgument" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="RegExpAnonymousGroup" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ReplaceCollectionCountWithSize" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="ReplaceNotNullAssertionWithElvisReturn" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="RestrictReturnStatementTargetMigration" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ResultSetIndexZero" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ReturnNull" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_reportObjectMethods" value="true" />
<option name="m_reportArrayMethods" value="true" />
<option name="m_reportCollectionMethods" value="true" />
<option name="m_ignorePrivateMethods" value="false" />
</inspection_tool>
<inspection_tool class="ReturnOfInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ReturnThis" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RuntimeExec" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RuntimeExecWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SafeLock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SamePackageImport" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SerialPersistentFieldsWithWrongSignature" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SerializableCtor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SerializableInnerClassHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreAnonymousInnerClasses" value="false" />
<option name="superClassString" value="java.awt.Component" />
</inspection_tool>
<inspection_tool class="SerializableInnerClassWithNonSerializableOuterClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreAnonymousInnerClasses" value="false" />
<option name="superClassString" value="java.awt.Component" />
</inspection_tool>
<inspection_tool class="SerializableStoresNonSerializable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SerializableWithUnconstructableAncestor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SetReplaceableByEnumSet" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SharedThreadLocalRandom" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SignalWithoutCorrespondingAwait" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SimpleDateFormatWithoutLocale" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SimplifiableAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SimplifiableEqualsExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SingleCharacterStartsWith" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="Singleton" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SleepWhileHoldingLock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SocketResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="insideTryAllowed" value="false" />
</inspection_tool>
<inspection_tool class="StandardVariableNames" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticCallOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticCollection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreWeakCollections" value="false" />
</inspection_tool>
<inspection_tool class="StaticFieldReferenceOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticGuardedByInstance" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticImport" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticInheritance" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticNonFinalField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticPseudoFunctionalStyleMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticVariableInitialization" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignorePrimitives" value="false" />
</inspection_tool>
<inspection_tool class="StaticVariableUninitializedUse" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignorePrimitives" value="false" />
</inspection_tool>
<inspection_tool class="StringBufferField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringBufferMustHaveInitialCapacity" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringBufferToStringInConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringConcatenation" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreAsserts" value="false" />
<option name="ignoreSystemOuts" value="false" />
<option name="ignoreSystemErrs" value="false" />
<option name="ignoreThrowableArguments" value="false" />
<option name="ignoreConstantInitializers" value="false" />
<option name="ignoreInTestCode" value="false" />
<option name="ignoreInToString" value="false" />
</inspection_tool>
<inspection_tool class="StringConcatenationArgumentToLogCall" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringConcatenationInFormatCall" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringConcatenationInMessageFormatCall" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringConcatenationMissingWhitespace" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringReplaceableByStringBuffer" enabled="true" level="WARNING" enabled_by_default="true">
<option name="onlyWarnOnLoop" value="true" />
</inspection_tool>
<inspection_tool class="StringToUpperWithoutLocale" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringTokenizer" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SubtractionInCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SuperTearDownInFinally" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SuspiciousArrayCast" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SuspiciousLiteralUnderscore" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SuspiciousLocalesLanguages" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SwitchStatementDensity" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="20" />
</inspection_tool>
<inspection_tool class="SwitchStatementWithTooManyBranches" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="10" />
</inspection_tool>
<inspection_tool class="SynchronizationOnStaticField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SynchronizeOnLock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SynchronizeOnThis" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_includeNativeMethods" value="true" />
<option name="ignoreSynchronizedSuperMethods" value="true" />
</inspection_tool>
<inspection_tool class="SynchronizedOnLiteralObject" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SystemExit" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SystemGC" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SystemGetenv" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SystemOutErr" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SystemProperties" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SystemSetSecurityManager" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TestCaseWithConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TestCaseWithNoTestMethods" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TestInProductSource" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TestMethodWithoutAssertion" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TestOnlyProblems" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThreadDeathRethrown" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThreadDumpStack" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThreadLocalNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThreadPriority" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThreadStartInConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThreadStopSuspendResume" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThreadYield" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThreadingConcurrency" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ThreeNegationsPerMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreInEquals" value="true" />
<option name="ignoreInAssert" value="false" />
</inspection_tool>
<inspection_tool class="ThrowCaughtLocally" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreRethrownExceptions" value="false" />
</inspection_tool>
<inspection_tool class="ThrownExceptionsPerMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_limit" value="3" />
</inspection_tool>
<inspection_tool class="ThrowsRuntimeException" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TimeToString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TodoComment" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TooBroadCatch" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TooBroadThrows" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TransientFieldInNonSerializableClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TransientFieldNotInitialized" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TypeMayBeWeakened" enabled="true" level="WARNING" enabled_by_default="true">
<option name="useRighthandTypeAsWeakestTypeInAssignments" value="true" />
<option name="useParameterizedTypeForCollectionMethods" value="true" />
<option name="doNotWeakenToJavaLangObject" value="true" />
<option name="onlyWeakentoInterface" value="true" />
</inspection_tool>
<inspection_tool class="TypeParameterExtendsFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UncheckedExceptionClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnconditionalWait" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UndeclaredTests" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnknownGuard" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessarilyQualifiedStaticUsage" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreStaticFieldAccesses" value="false" />
<option name="m_ignoreStaticMethodCalls" value="false" />
<option name="m_ignoreStaticAccessFromStaticContext" value="false" />
</inspection_tool>
<inspection_tool class="UnnecessarilyQualifiedStaticallyImportedElement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryConstantArrayCreationExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryExplicitNumericCast" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryFinalOnLocalVariableOrParameter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryInheritDoc" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryJavaDocLink" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreInlineLinkToSuper" value="false" />
</inspection_tool>
<inspection_tool class="UnnecessaryQualifierForThis" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessarySuperQualifier" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryThis" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnqualifiedInnerClassAccess" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreReferencesToLocalInnerClasses" value="true" />
</inspection_tool>
<inspection_tool class="UnsecureRandomNumberGeneration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnstableTypeUsedInSignature" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnusedDefine" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnusedLibrary" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnusedMainParameter" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="UpperCaseFieldNameNotConstant" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseEllipsisInPropertyInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseOfAWTPeerClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseOfAnotherObjectsPrivateField" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreSameClass" value="false" />
<option name="ignoreEquals" value="false" />
</inspection_tool>
<inspection_tool class="UseOfClone" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseOfJDBCDriverClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseOfObsoleteAssert" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseOfObsoleteDateTimeApi" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseOfProcessBuilder" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseOfPropertiesAsHashtable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseOfSunClasses" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UsePlatformProcessAwaitExit" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="UtilityClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignorableAnnotations">
<value />
</option>
</inspection_tool>
<inspection_tool class="UtilityClassCanBeEnum" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UtilityClassWithPublicConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UtilityClassWithoutPrivateConstructor" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignorableAnnotations">
<value />
</option>
<option name="ignoreClassesWithOnlyMain" value="false" />
</inspection_tool>
<inspection_tool class="VariableNotUsedInsideIf" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="VolatileArrayField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="WaitCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="WaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="WaitNotifyNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="WaitOrAwaitWithoutTimeout" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="WaitWithoutCorrespondingNotify" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="WarningOnMainUnusedParameterMigration" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="WhenWithOnlyElse" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="ZeroLengthArrayInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
+40
View File
@@ -0,0 +1,40 @@
# Titanboard
Titanboard is an input method for physical keyboard phones, supporting as low as Android 1.5
Cupcake.
## Features
- Support for very low Android versions, down to 1.5
- Nimble and small; I set out to have the APK be at most 100 kB
- Each physical key can have several additional symbols, which the user can cycle by long pressing
a given key. This also applies for alternate (alt) symbols
- 9 supported languages, with more planned (which are trivial to add)
- No hard to memorize key combinations; reasonably uses what the physical keyboard has to offer
- Clipboard management
## Planned features
- Autocorrect
- Emojis
- Support for content other than text in clipboard
- Floating interface, which is placed over the current text in certain contexts, to save screen
space
## Supported languages
- English
- German
- French
- Italian
- Spanish
- Polish
- Russian (Phonetic)
- Greek (polytonic diacritics under Q)
- Arabic (Phonetic)
## Supported devices
Thus far, the supported devices are:
- Unihertz Titan (additional diacritics under 1 key for all languages)
-96
View File
@@ -1,96 +0,0 @@
# Titanboard user experience
Keyboards are an integral part of the functioning of any computer, including the smartphone. Care
should then be taken to design keyboards to be as intuitive, easy to use, and unobstructed as
possible.
The Unihertz Titan already has a physical keyboard. It's poorly designed in many aspects. Mainly, it
isn't very reminiscent of a regular QWERTY keyboard which people are used to:
1. The worst part is arguably the shift and alt keys being at the top of the keyboard, instead of on
the bottom.
2. The spacebar key is on the same row as the bottom QWERTY alphabet keys.
3. The numerical keys, which are some of the most commonly used keys in phones (passwords, PIN
codes)
and in regular language are right below the alt key, which makes typing them very awkward. One
could
also argue that the numpad is in a "reversed" layout, but this is consistent with the usual
layout
found on phones.
4. It lacks some commonly used symbols: ';', '&', '=', '<', '>', '$'. Other than that, it lacks some
other
symbols from regular QWERTY keyboards.
5. There is no extra alt-gr key to type in localized letters.
6. The keyboard is too big for one hand typing.
7. In my opinion, it also lacks a control key, but that is unnecessary on smartphones, unless you
use the terminal or modify spreadsheets. However, providing appropriate UI elements for the
actions
possible on regular computers should be the responsibility of the application. Smartphones are
simply different devices, with smaller screens and less space for complexity.
8. Emojis.
However, when designing a keyboard app for it one should already use all pre-existing quirks and
decisions which materialized in the physical keyboard. For example, the alt key should be used for
the alternate characters printed on the keyboard, the shift key should give us uppercase characters
and so on.
# Solutions
Here are my solutions for the above listed problems:
1. This is solvable with shift/alt latching. This makes it so when you press these keys once, the
next key pressed will be either uppercased or the alternate key visible on the physical button.
Additionally, the shift and alt key can be toggled by double-clicking in a fast succession, similar
to regular visual keyboards on Android.
2. This is unfortunately unsolvable with software.
3. See 1., latching the keys solves this issue.
4. This is solved by assigning alternate symbols when alt is pressed/latched/locked and the given
key is long pressed. A menu pops up, and as you hold the key the symbols are cycled through.
5. Similar to regular visual keyboards on Android, a diacritic/alternate key is assigned to each key
according to the language. Long pressing a key will allow you to cycle through available
alternatives.
6. A toggleable UI that shows the left/right hand side keys, depending on a customizable setting for
left handed people.
7. I have no plans on adding a control key, as it is largely unnecessary on phones.
8. I do not really use emojis, but I am aware that they are used by the majority of people. Most
IM apps provide their own emoji list, so this isn't a priority. Designing a good UX for it is also
hard on the Titan.
Taking into account typing ergonomics and pre-existing UX choices of other keyboard designers, this
input method should make typing on the Unihertz Titan a pleasant experience. Other than fixing the
fundamental issues, the keyboard should also:
1. Provide a way of managing the clipboard, or at the very least pasting things with an UI element.
This is to make the usage intuitive and not introduce any additional keys such as a ctrl key.
2. Autocorrect, language switching, auto caps and periods.
3. Some minimal customization, but just enough not to overwhelm the user.
For the Unihertz Titan Pocket/Slim, the sym key is unused. I have no ideas what it could be useful
for. It can be set in Unihertz's software to do operating system actions, which I think is good.
# User interface
Google recommends that visual keyboards should not occupy more than half of the screen estate.
However, most phones have long, vertical screens, which means essentially that the keyboard will
be a square, and so will the remaining view. On the Titan, the screen is already square, so the
remaining space will be proportionally much smaller. Therefore, the keyboard should occupy very
minimal screen estate, as to allow the user to see the application they are interacting with.
For this reason, I make sure the keyboard occupies 20–25 % screen estate. This is enough for simple
status bar, which shows the current shift/alt state, the current language, and a symbol bar which
appears when long pressing keys.
# Keymaps
Latin keymaps use the regular QWERTY layout of the Titan. There is one, large, general European key
layout, which contains all characters used in Europe.
## European
German has the most speakers, therefore it's diacritics are the first in the list. Then French and
Italian, which have similar diacritics. These come next. Afterwards, Spanish, then Polish, and the
rest.
## Cyrillic
Regular JCUKEN layout, with additional characters for other non-Russian languages.
## Greek
Works mostly like a regular Greek QWERTY keyboard.
+18 -9
View File
@@ -3,25 +3,33 @@ plugins {
}
android {
namespace 'cfpi_fpsi.eu.titanboard'
compileSdk 34
namespace 'eur.cfpifpsi.titanboard'
compileSdk 35
defaultConfig {
applicationId "cfpi_fpsi.eu.titanboard"
minSdk 19
//noinspection OldTargetApi
targetSdk 34
versionCode 30
versionName "0.3"
applicationId 'eur.cfpifpsi.titanboard'
minSdk 3
targetSdk 35
versionCode 31
versionName '0.3.1'
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
debug {
minifyEnabled false
shrinkResources false
applicationIdSuffix '.debug'
versionNameSuffix '-DEBUG'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@@ -30,3 +38,4 @@ android {
+28 -7
View File
@@ -1,25 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_CLIPBOARD" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/icon"
android:icon="@drawable/ic_app"
android:label="@string/app_name"
android:roundIcon="@drawable/ic_app_round"
android:supportsRtl="true"
tools:targetApi="31">
<profileable
android:shell="true"
tools:targetApi="q" />
<service
android:name=".InputMethod"
android:name=".TitanboardIME"
android:directBootAware="true"
android:exported="false"
android:icon="@drawable/icon"
android:label="@string/ime_label"
android:label="@string/app_name"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data
android:name="android.view.im"
android:resource="@xml/method" />
@@ -28,7 +49,7 @@
<activity
android:name=".SettingsActivity"
android:exported="false"
android:label="@string/preferences_label">
android:label="@string/preferences_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
@@ -1,216 +0,0 @@
/*
* An input method for the Unihertz Titan/physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
package cfpi_fpsi.eu.titanboard;
import android.annotation.SuppressLint;
import android.inputmethodservice.InputMethodService;
import android.os.Vibrator;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// TODO: Implement auto-correct.
// TODO: Implement device recognition and a keymap picking based on it.
// TODO: Mode without the bottom input view, in case the user does not care about completions.
// This will involve making a popup screen and a shortcut for changing languages.
public class InputMethod extends InputMethodService {
public MetaKeyManager mMetaKeyManager;
public KeymapManager mKeymapManager;
public InputView mInputView;
public Settings mSettings;
public int mCurrentCursorPosition;
private SymbolCycler mSymbolCycler;
private long mLastKeyTime;
private int mSymbolPressed;
@Override
public void onCreate() {
super.onCreate();
mSettings = new Settings(this);
Vibrator mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
mMetaKeyManager = new MetaKeyManager(mVibrator);
mKeymapManager = new KeymapManager(this);
mSymbolCycler = new SymbolCycler(this);
mKeymapManager.cycleKeymaps(mSettings.getSelectedKeymaps());
}
@SuppressLint("InflateParams")
@Override
public void onInitializeInterface() {
mInputView = (InputView) getLayoutInflater().inflate(R.layout.input, null);
mInputView.updateStateText();
}
@Override
public boolean onEvaluateFullscreenMode() {
// This is to override the default behaviour, which seems to do more than detect landscape
// mode.
return false;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
mMetaKeyManager.updateMetaStateDown(keyCode);
mInputView.updateStateText();
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (isInputViewShown()) {
requestHideSelf(0);
return true;
}
return false;
case KeyEvent.KEYCODE_DEL:
case KeyEvent.KEYCODE_ENTER:
mMetaKeyManager.adjustMetaStateAfterKeypress();
return false;
case KeyEvent.KEYCODE_SPACE:
handleSpacebar(event);
return true;
default:
ArrayList<String> symbols = mKeymapManager.getSymbols(keyCode, mMetaKeyManager);
if (symbols == null) {
return false;
}
if (event.getRepeatCount() == 0 && !symbols.isEmpty()) {
getCurrentInputConnection().commitText(symbols.get(0), 1);
mMetaKeyManager.adjustMetaStateAfterKeypress();
mInputView.updateStateText();
mSymbolPressed = keyCode;
mLastKeyTime = event.getEventTime();
mSymbolCycler.stopCycling();
mSymbolCycler.startCycling(symbols, getCurrentInputConnection());
if (!mSettings.isCyclingWithSpaceEnabled()) {
mSymbolCycler.startAutomaticCycling();
}
}
return true;
}
}
public void handleSpacebar(KeyEvent event) {
InputConnection conn = getCurrentInputConnection();
if (mSettings.isCyclingWithSpaceEnabled()
&& mSymbolPressed != -1 && event.getEventTime() - mLastKeyTime > 200) {
mSymbolCycler.cycle();
return;
}
if (mSettings.isAutoPeriodsEnabled()) {
String text = getTextBeforeCursor(2);
if (!text.isEmpty()) {
Pattern pattern = Pattern.compile("[^\\.… ]+ $");
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
// InputConnection.replaceSelection needs a higher API, so we just do exactly
// what it does to support more devices.
conn.finishComposingText();
conn.setSelection(mCurrentCursorPosition - 1, mCurrentCursorPosition);
conn.commitText(".", 1);
}
}
}
conn.commitText(" ", 1);
mMetaKeyManager.adjustMetaStateAfterKeypress();
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (mSymbolPressed == keyCode) {
mSymbolPressed = -1;
mSymbolCycler.stopCycling();
mInputView.updateSymbolsView(null, 0);
}
// TODO: Not ideal. Should be handled on key down ideally.
if (keyCode == KeyEvent.KEYCODE_DEL) {
detectAutoCapitalization();
}
getCurrentInputConnection().finishComposingText();
mMetaKeyManager.updateMetaStateUp(keyCode, event);
mInputView.updateStateText();
return false;
}
@Override
public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd,
int candidatesStart, int candidatesEnd) {
mCurrentCursorPosition = newSelStart;
detectAutoCapitalization();
}
public String getTextBeforeCursor(int n) {
CharSequence chars = getCurrentInputConnection().getTextBeforeCursor(n, 0);
return chars == null ? "" : String.valueOf(chars);
}
public void detectAutoCapitalization() {
if (!mSettings.isAutoCapsEnabled()) {
return;
}
// Get a bunch of text, run a regex through it, and bam. Is there a better way to do this?
String text = getTextBeforeCursor(16);
if (text.isEmpty()) {
mMetaKeyManager.getShift().setLatched(true);
mInputView.updateStateText();
} else {
// If, on the other hand, we have some characters before the cursor, we scan.
Pattern pattern = Pattern.compile("[\\.…\\!\\?] +$");
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
mMetaKeyManager.getShift().setLatched(true);
mInputView.updateStateText();
}
}
}
@Override
public View onCreateInputView() {
return mInputView;
}
@Override
public void onStartInput(EditorInfo info, boolean restarting) {
super.onStartInput(info, restarting);
detectAutoCapitalization();
mKeymapManager.checkCurrentKeymap(mSettings.getSelectedKeymaps());
mInputView.updateStateText();
}
@Override
public void onFinishInput() {
mMetaKeyManager.resetMetaKeyState();
mInputView.updateStateText();
}
}
@@ -1,126 +0,0 @@
/*
* An input method for the Unihertz Titan/physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
package cfpi_fpsi.eu.titanboard;
import android.content.Context;
import android.content.Intent;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
public class InputView extends RelativeLayout {
private final InputMethod mInputMethod;
private Button mStateButton;
private LinearLayout mMultiList;
public InputView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
mInputMethod = (InputMethod) context;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mMultiList = findViewById(R.id.multi_list);
mStateButton = findViewById(R.id.input_state);
mStateButton.setOnClickListener(button -> {
MetaKeyManager metaManager = mInputMethod.mMetaKeyManager;
if (metaManager.getAlt().isActive()) {
metaManager.getAlt().resetState();
} else {
mInputMethod.mKeymapManager.cycleKeymaps(mInputMethod.mSettings.getSelectedKeymaps());
}
updateStateText();
});
mStateButton.setOnLongClickListener(button -> {
Intent intent = new Intent(getContext(), SettingsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
return true;
});
}
public void updateStateText() {
MetaKeyManager metaManager = mInputMethod.mMetaKeyManager;
KeymapManager keymapManager = mInputMethod.mKeymapManager;
mStateButton.setPaintFlags(mStateButton.getPaintFlags() & ~(Paint.UNDERLINE_TEXT_FLAG));
if (metaManager.getAlt().isPressed()) {
mStateButton.setText(R.string.inputview_symbols_locked_state);
return;
}
if (metaManager.getAlt().isLocked()) {
mStateButton.setText(R.string.inputview_symbols_locked_state);
mStateButton.setPaintFlags(mStateButton.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
return;
}
if (metaManager.getAlt().isLatched()) {
mStateButton.setText(R.string.inputview_symbols_latched_state);
return;
}
if (metaManager.getShift().isPressed()) {
mStateButton.setText(keymapManager.getCurrentKeymap().getLockedCode());
return;
}
if (metaManager.getShift().isLocked()) {
mStateButton.setText(keymapManager.getCurrentKeymap().getLockedCode());
mStateButton.setPaintFlags(mStateButton.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
return;
}
if (metaManager.getShift().isLatched()) {
mStateButton.setText(keymapManager.getCurrentKeymap().getLatchedCode());
return;
}
mStateButton.setText(keymapManager.getCurrentKeymap().getCode());
}
public void updateSymbolsView(ArrayList<String> symbols, int index) {
for (int i = 0; i < mMultiList.getChildCount(); ++i) {
TextView view = (TextView) mMultiList.getChildAt(i);
view.setText("");
}
if (symbols != null) {
for (int i = 0; i < Math.min(mMultiList.getChildCount(), symbols.size()); ++i) {
TextView view = (TextView) mMultiList.getChildAt(i);
view.setText(symbols.get(i));
if (i == index) {
view.setTextAppearance(getContext(), R.style.InputViewSymbolSelected);
} else {
view.setTextAppearance(getContext(), R.style.InputViewSymbol);
}
}
}
}
}
@@ -1,207 +0,0 @@
/*
* An input method for the Unihertz Titan/physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
package cfpi_fpsi.eu.titanboard;
import android.content.Context;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
public class KeymapManager {
private final Context mContext;
private final HashMap<String, Keymap> mKeymaps = new HashMap<>();
public Keymap mCurrentKeymap;
public KeymapManager(Context context) {
mContext = context;
loadDeviceKeymaps(mContext.getResources().getXml(R.xml.keymaps_titan));
}
private void loadDeviceKeymaps(XmlPullParser parser) {
Keymap keymap = null;
int code = 0;
String name = null, latchedName = null, lockedName = null;
Key key = null;
try {
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
int type = parser.getEventType();
// We encounter a new keymap.
if (type == XmlPullParser.START_TAG && parser.getName().equals("keymap")) {
keymap = new Keymap();
for (int i = 0; i < parser.getAttributeCount(); ++i) {
switch (parser.getAttributeName(i)) {
case "name":
name = parser.getAttributeValue(i);
break;
case "latched-name":
latchedName = parser.getAttributeValue(i);
break;
case "locked-name":
lockedName = parser.getAttributeValue(i);
break;
}
}
} else if (type == XmlPullParser.END_TAG && parser.getName().equals("keymap")
&& keymap != null) {
keymap.setStrings(name, latchedName, lockedName);
mKeymaps.put(name, keymap);
}
// We got a new key.
if (type == XmlPullParser.START_TAG && parser.getName().equals("key")) {
key = new Key();
for (int i = 0; i < parser.getAttributeCount(); ++i) {
if (parser.getAttributeName(i).equals("code")) {
code = Integer.parseInt(parser.getAttributeValue(i));
}
}
} else if (type == XmlPullParser.END_TAG && parser.getName().equals("key")
&& keymap != null) {
keymap.put(code, key);
}
// We encountered a base value.
if (type == XmlPullParser.START_TAG && parser.getName().equals("base")) {
for (int i = 0; i < parser.getAttributeCount(); ++i) {
if (parser.getAttributeName(i).startsWith("value") && key != null) {
key.getSymbolsBase().add(parser.getAttributeValue(i));
}
}
}
// We encountered a shift value.
if (type == XmlPullParser.START_TAG && parser.getName().equals("shift")) {
for (int i = 0; i < parser.getAttributeCount(); ++i) {
if (parser.getAttributeName(i).startsWith("value") && key != null) {
key.getSymbolsShift().add(parser.getAttributeValue(i));
}
}
}
// We encountered an alt value.
if (type == XmlPullParser.START_TAG && parser.getName().equals("alt")) {
for (int i = 0; i < parser.getAttributeCount(); ++i) {
if (parser.getAttributeName(i).startsWith("value") && key != null) {
key.getSymbolsAlt().add(parser.getAttributeValue(i));
}
}
}
parser.next();
}
} catch (XmlPullParserException | IOException e) {
throw new RuntimeException(e);
}
}
public ArrayList<String> getSymbols(int keyCode, MetaKeyManager metaKeyManager) {
if (metaKeyManager.getAlt().isActive()) {
return getCurrentKeymap().getSymbolsAlt(keyCode);
}
if (metaKeyManager.getShift().isActive()) {
return getCurrentKeymap().getSymbolsShift(keyCode);
}
return getCurrentKeymap().getSymbolsBase(keyCode);
}
public void checkCurrentKeymap(ArrayList<String> selectedKeymaps) {
if (!selectedKeymaps.contains(mCurrentKeymap.mCode)) {
cycleKeymaps(selectedKeymaps);
}
}
public void cycleKeymaps(ArrayList<String> selectedKeymaps) {
if (selectedKeymaps.isEmpty() || mCurrentKeymap == null) {
mCurrentKeymap = mKeymaps.get(mContext.getResources().getString(R.string.keymap_default));
return;
}
int index = selectedKeymaps.indexOf(mCurrentKeymap.mCode);
index++;
if (index == selectedKeymaps.size()) {
index = 0;
}
mCurrentKeymap = mKeymaps.get(selectedKeymaps.get(index));
}
public Keymap getCurrentKeymap() { return mCurrentKeymap; }
public static class Keymap extends HashMap<Integer, Key> {
private String mCode; // A two-letter code for when the keyboard is lowercase.
private String mLatchedCode; // Above, but when the keyboard is shift latched.
private String mLockedCode; // Above, but when the shift is locked/pressed.
public String getCode() {
return mCode;
}
public String getLatchedCode() {
return mLatchedCode;
}
public String getLockedCode() {
return mLockedCode;
}
public void setStrings(String code, String latched, String locked) {
mCode = code;
mLatchedCode = latched;
mLockedCode = locked;
}
public ArrayList<String> getSymbolsBase(int keyCode) {
return get(keyCode) != null ? get(keyCode).getSymbolsBase() : null;
}
public ArrayList<String> getSymbolsAlt(int keyCode) {
return get(keyCode) != null ? get(keyCode).getSymbolsAlt() : null;
}
public ArrayList<String> getSymbolsShift(int keyCode) {
return get(keyCode) != null ? get(keyCode).getSymbolsShift() : null;
}
}
public static class Key {
private final ArrayList<String> mSymbolsBase = new ArrayList<>();
private final ArrayList<String> mSymbolsShift = new ArrayList<>();
private final ArrayList<String> mSymbolsAlt = new ArrayList<>();
public ArrayList<String> getSymbolsBase() {
return mSymbolsBase;
}
public ArrayList<String> getSymbolsShift() {
return mSymbolsShift;
}
public ArrayList<String> getSymbolsAlt() {
return mSymbolsAlt;
}
}
}
@@ -1,172 +0,0 @@
/*
* An input method for the Unihertz Titan/physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
package cfpi_fpsi.eu.titanboard;
import android.os.Vibrator;
import android.view.KeyEvent;
public class MetaKeyManager {
public final MetaKey mShift = new MetaKey();
public final MetaKey mAlt = new MetaKey();
private final Vibrator mVibrator;
public MetaKeyManager(Vibrator vibrator) {
mVibrator = vibrator;
}
public void updateMetaStateDown(int keyCode) {
switch (keyCode) {
case KeyEvent.KEYCODE_ALT_LEFT:
case KeyEvent.KEYCODE_ALT_RIGHT:
updateMetaKeyDown(mAlt);
break;
case KeyEvent.KEYCODE_SHIFT_LEFT:
case KeyEvent.KEYCODE_SHIFT_RIGHT:
updateMetaKeyDown(mShift);
break;
default:
break;
}
}
void updateMetaKeyDown(MetaKey key) {
// Perhaps this function should be renamed to something...
key.setUsed(false);
key.setPressed(true);
key.setLatched(key.isLocked() ? key.isLocked() : key.isLatched());
key.setLocked(false);
}
public void updateMetaStateUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_ALT_LEFT:
case KeyEvent.KEYCODE_ALT_RIGHT:
updateMetaKeyUp(mAlt, event);
break;
case KeyEvent.KEYCODE_SHIFT_LEFT:
case KeyEvent.KEYCODE_SHIFT_RIGHT:
updateMetaKeyUp(mShift, event);
break;
default:
break;
}
}
public void updateMetaKeyUp(MetaKey key, KeyEvent event) {
if (event.getEventTime() - key.getKeyUpTime() < 400) {
key.setLocked(true);
mVibrator.vibrate(30);
}
key.setKeyUpTime(event.getEventTime());
key.setPressed(false);
key.setLatched(!key.isLatched() && !key.isLocked() && !key.isUsed());
}
public void adjustMetaStateAfterKeypress() {
adjustMetaStateHelper(mShift);
adjustMetaStateHelper(mAlt);
}
public void adjustMetaStateHelper(MetaKey key) {
if (key.isLatched()) {
key.setLatched(false);
key.setUsed(false);
}
if (key.isPressed()) {
key.setUsed(true);
}
}
public void resetMetaKeyState() {
mShift.resetState();
mAlt.resetState();
}
public MetaKey getShift() {
return mShift;
}
public MetaKey getAlt() {
return mAlt;
}
public static class MetaKey {
private boolean mPressed = false;
private boolean mLatched = false;
private boolean mLocked = false;
private boolean mUsed = false;
private long mKeyUpTime;
public void resetState() {
setPressed(false);
setLatched(false);
setLocked(false);
setUsed(false);
}
public boolean isPressed() {
return mPressed;
}
public void setPressed(boolean state) {
mPressed = state;
}
public boolean isLatched() {
return mLatched;
}
public void setLatched(boolean state) {
mLatched = state;
}
public boolean isLocked() {
return mLocked;
}
public void setLocked(boolean state) {
mLocked = state;
}
public boolean isUsed() {
return mUsed;
}
public void setUsed(boolean state) {
mUsed = state;
}
public boolean isActive() {
return isPressed() || isLocked() || isLatched();
}
public long getKeyUpTime() {
return mKeyUpTime;
}
public void setKeyUpTime(long time) {
mKeyUpTime = time;
}
}
}
@@ -1,74 +0,0 @@
/*
* An input method for the Unihertz Titan/physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
package cfpi_fpsi.eu.titanboard;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.view.inputmethod.InputConnection;
import java.util.ArrayList;
public class SymbolCycler extends Handler {
private final InputMethod mInputMethod;
private final SymbolCyclerRunnable mRunnable;
private int mIndex;
private ArrayList<String> mSymbols;
private InputConnection mConn;
public SymbolCycler(Context context) {
super(Looper.getMainLooper());
mInputMethod = (InputMethod) context;
mRunnable = new SymbolCyclerRunnable();
}
public void startCycling(ArrayList<String> symbols, InputConnection conn) {
mSymbols = symbols;
mConn = conn;
mIndex = 0;
}
public void startAutomaticCycling() {
postDelayed(mRunnable, mInputMethod.mSettings.getCycleSpeed());
}
public void stopCycling() {
removeCallbacks(mRunnable);
}
public void cycle() {
mIndex++;
if (mIndex == mSymbols.size()) {
mIndex = 0;
}
mInputMethod.mInputView.updateSymbolsView(mSymbols, mIndex);
mConn.setComposingRegion(mInputMethod.mCurrentCursorPosition - 1, mInputMethod.mCurrentCursorPosition);
mConn.setComposingText(mSymbols.get(mIndex), 1);
}
private class SymbolCyclerRunnable implements Runnable {
@Override
public void run() {
cycle();
postDelayed(this, mInputMethod.mSettings.getCycleSpeed());
}
}
}
@@ -1,35 +0,0 @@
/*
* An input method for the Unihertz Titan/physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
package cfpi_fpsi.eu.titanboard;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
public class SymbolsView extends RelativeLayout {
public SymbolsView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
}
}
@@ -0,0 +1,82 @@
/*
* An input method for physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package eur.cfpifpsi.titanboard;
import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Build;
import java.util.ArrayList;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class ClipManager implements ClipboardManager.OnPrimaryClipChangedListener {
private final TitanboardIME mTitanboardIME;
private final ClipboardManager mClipboardManager;
private final ArrayList<ClipData.Item> mClips;
private long mLastCallbackTimestamp;
public ClipManager(Context context) {
mTitanboardIME = (TitanboardIME) context;
mClips = new ArrayList<>(mTitanboardIME.mPreferenceHolder.getClipboardSize());
mClipboardManager = (ClipboardManager)
mTitanboardIME.getSystemService(Context.CLIPBOARD_SERVICE);
mClipboardManager.addPrimaryClipChangedListener(this);
}
@Override
public void onPrimaryClipChanged() {
// The callback can be launched several times at once, so we have to check if it isn't the
// same clipboard data.
if (System.currentTimeMillis() - mLastCallbackTimestamp >= 100) {
mLastCallbackTimestamp = System.currentTimeMillis();
ClipData clip = mClipboardManager.getPrimaryClip();
if (clip != null) {
int itemCount = clip.getItemCount();
for (int i = 0; i < itemCount; ++i) {
ClipData.Item item = clip.getItemAt(i);
// We do not support non-text clips for now, so all we add are text clips.
if (item.getText() != null) {
mClips.add(0, item);
}
if (mClips.size() > mTitanboardIME.mPreferenceHolder.getClipboardSize()) {
mClips.remove(mClips.size() - 1);
}
}
mTitanboardIME.mInputView.setClips(mClips);
}
}
}
public boolean isEmpty() {
return mClips.isEmpty();
}
public void removeItem(ClipData.Item item) {
mClips.remove(item);
}
public ClipData.Item getItemAt(int index) {
return mClips.get(index);
}
}
@@ -0,0 +1,69 @@
/*
* An input method for physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package eur.cfpifpsi.titanboard;
import java.util.ArrayList;
public abstract class Cycler implements Runnable {
private static final int LIST_INITIAL_SIZE = 10;
private ArrayList<?> mList = new ArrayList<>(LIST_INITIAL_SIZE);
private boolean mHasCycled;
private int mIndex;
public int getIndex() {
return mIndex;
}
public ArrayList<?> getList() {
return mList;
}
public Object getElementAt(int index) {
return mList.get(index);
}
public Object getCurrentElement() {
return getElementAt(mIndex);
}
public void prepare(ArrayList<?> list) {
mList = list;
mHasCycled = false;
mIndex = 0;
}
@Override
public void run() {
if (!mHasCycled) {
onFirstCycle();
mHasCycled = true;
}
++mIndex;
if (mIndex >= mList.size()) {
mIndex = 0;
}
onCycle();
}
public abstract void onFirstCycle();
public abstract void onCycle();
}
@@ -0,0 +1,231 @@
/*
* An input method for physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package eur.cfpifpsi.titanboard;
import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.Build;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import java.util.ArrayList;
// TODO: programmatically scroll if current selected symbol is outside the visible space of the
// scrollview
public final class InputView extends RelativeLayout {
private final int[] buttonStateToggled = {R.attr.state_toggled};
private final TitanboardIME mTitanboardIME;
private final LinearLayout.LayoutParams mSymbolLayout;
private final LinearLayout.LayoutParams mClipLayout;
public PopupWindow mClipboardPopup;
private LinearLayout mSymbolList;
private LinearLayout mClipList;
private Button mStateButton;
private ImageButton mClipboardButton;
public InputView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
mTitanboardIME = (TitanboardIME) context;
mSymbolLayout = new LinearLayout.LayoutParams(
getResources().getDimensionPixelSize(R.dimen.symbol_width),
ViewGroup.LayoutParams.MATCH_PARENT, 0);
mClipLayout = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 0);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mSymbolList = findViewById(R.id.symbol_list);
mStateButton = findViewById(R.id.state_button);
mClipboardButton = findViewById(R.id.clipboard_button);
ScrollView mClipboardView = (ScrollView) inflate(getContext(), R.layout.clipboard, null);
mClipList = mClipboardView.findViewById(R.id.clip_list);
mClipboardPopup = new PopupWindow(mClipboardView,
getResources().getDimensionPixelSize(R.dimen.clipboard_popup_width),
getResources().getDimensionPixelSize(R.dimen.clipboard_popup_height), true);
mClipboardPopup.setOnDismissListener(() -> mClipboardButton.setImageState(null, true));
mStateButton.setOnClickListener(button -> {
MetaKeyManager metaManager = mTitanboardIME.mMetaKeyManager;
if (metaManager.getAlt().isActive()) {
metaManager.getAlt().resetState();
} else {
mTitanboardIME.mKeymapManager
.nextKeymap(mTitanboardIME.mPreferenceHolder.getSelectedKeymaps());
}
updateStateText();
});
mStateButton.setOnLongClickListener(button -> {
Intent intent = new Intent(getContext(), SettingsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
// For some reason, this vibrates by default, so we don't need to call the vibrator.
return true;
});
mClipboardButton.setOnClickListener(button -> {
mClipboardPopup.showAsDropDown(mClipboardButton,
-(mClipboardPopup.getWidth() - mClipboardButton.getWidth()) / 2, 0);
mClipboardButton.setImageState(buttonStateToggled, true);
});
mClipboardButton.setOnLongClickListener(button -> {
// On a long click, we just send the latest clip (if any).
if (!mTitanboardIME.mClipManager.isEmpty()
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mTitanboardIME.getCurrentInputConnection()
.commitText(mTitanboardIME.mClipManager.getItemAt(0).getText(), 1);
}
return true;
});
}
/**
* @noinspection FeatureEnvy
*/
public void updateStateText() {
MetaKeyManager metaManager = mTitanboardIME.mMetaKeyManager;
KeymapManager keymapManager = mTitanboardIME.mKeymapManager;
mStateButton.setPaintFlags(mStateButton.getPaintFlags() & ~(Paint.UNDERLINE_TEXT_FLAG));
if (metaManager.getAlt().isLocked() || metaManager.getShift().isLocked()) {
mStateButton.setPaintFlags(mStateButton.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
}
if (metaManager.getAlt().isPressed() || metaManager.getAlt().isLocked()) {
mStateButton.setText(R.string.state_button_alt_locked);
return;
}
if (metaManager.getAlt().isLatched()) {
mStateButton.setText(R.string.state_button_alt_latched);
return;
}
if (metaManager.getShift().isPressed() || metaManager.getShift().isLocked()) {
mStateButton.setText(keymapManager.getCurrentLockedLabel());
return;
}
if (metaManager.getShift().isLatched()) {
mStateButton.setText(keymapManager.getCurrentLatchedLabel());
return;
}
mStateButton.setText(keymapManager.getCurrentLabel());
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void setClips(ArrayList<? extends ClipData.Item> items) {
int size = items.size();
for (int i = 0; i < size; ++i) {
ClipData.Item item = items.get(i);
LinearLayout clipView = (LinearLayout) mClipList.getChildAt(i);
if (clipView == null) {
clipView = (LinearLayout) inflate(getContext(), R.layout.clip, null);
clipView.setTag(i);
clipView.setLayoutParams(mClipLayout);
mClipList.addView(clipView);
}
Button pasteButton = clipView.findViewById(R.id.paste_button);
pasteButton.setText(item.getText());
pasteButton.setOnClickListener(button -> mTitanboardIME.getCurrentInputConnection()
.commitText(item.getText(), 1));
LinearLayout finalClipView = clipView;
clipView.findViewById(R.id.button_delete).setOnClickListener(button -> {
mClipList.removeView(finalClipView);
mTitanboardIME.mClipManager.removeItem(item);
});
}
}
public void setSymbolsVisible(boolean state) {
mSymbolList.setVisibility(state ? VISIBLE : GONE);
}
/**
* @noinspection MethodWithMultipleLoops
*/
public void setSymbols(ArrayList<String> strings) {
int size = strings.size();
for (int i = 0; i < size; ++i) {
TextView tv = (TextView) mSymbolList.getChildAt(i);
if (tv == null) {
tv = (TextView) inflate(getContext(), R.layout.symbol, null);
tv.setTag(i);
tv.setLayoutParams(mSymbolLayout);
mSymbolList.addView(tv);
}
tv.setText(strings.get(i));
tv.setVisibility(VISIBLE);
}
int childCount = mSymbolList.getChildCount();
for (int i = size; i < childCount; ++i) {
mSymbolList.getChildAt(i).setVisibility(GONE);
}
}
public void setSelectedSymbol(int index) {
int childCount = mSymbolList.getChildCount();
for (int i = 0; i < childCount; ++i) {
TextView tv = (TextView) mSymbolList.getChildAt(i);
if (i == index) {
HorizontalScrollView hsw = findViewById(R.id.symbol_list_container);
tv.setPressed(true);
tv.setTypeface(null, Typeface.BOLD);
// This, if the symbol list is larger than the scroll view, scrolls it just to show
// the selected symbol at the very end. It isn't really necessary, as it's a rarity
// that a key has more than five symbols, but perhaps someone will want to add a
// keymap that has a lot of symbols under one key, and also this is a safeguard for
// smaller screen sizes.
hsw.smoothScrollTo(tv.getRight()
+ (getResources().getDimensionPixelSize(R.dimen.default_space) << 1)
- hsw.getRight(), 0);
} else {
tv.setPressed(false);
tv.setTypeface(null, Typeface.NORMAL);
}
}
}
}
@@ -0,0 +1,240 @@
/*
* An input method for physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package eur.cfpifpsi.titanboard;
import android.content.Context;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class KeymapManager {
private static final String TAG_KEY = "key"; //NON-NLS
private static final String TAG_KEYMAP = "keymap"; //NON-NLS
private static final String TAG_BASE = "base"; //NON-NLS
private static final String TAG_ALT = "alt"; //NON-NLS
private static final String TAG_SHIFT = "shift"; //NON-NLS
private static final String ATTR_CODE = "code"; //NON-NLS
private static final String ATTR_VALUE = "value"; //NON-NLS
private static final String ATTR_LABEL = "label"; //NON-NLS
private static final String ATTR_LATCHED_LABEL = "latched-label"; //NON-NLS
private static final String ATTR_LOCKED_LABEL = "locked-label"; //NON-NLS
private final Context mContext;
private final HashMap<String, Keymap> mKeymaps;
private Keymap mCurrentKeymap;
public KeymapManager(Context context) {
mContext = context;
mKeymaps = new HashMap<>(context.getResources()
.getStringArray(R.array.preferences_keymaps).length);
loadDeviceKeymaps(context.getResources().getXml(R.xml.keymaps_titan));
}
/**
* @noinspection BreakStatement
*/
private void loadDeviceKeymaps(XmlPullParser parser) {
Keymap keymap = null;
int code = 0;
String label = null, latchedLabel = null, lockedLabel = null;
Key key = null;
while (true) {
int eventType;
try {
eventType = parser.getEventType();
} catch (XmlPullParserException e) {
break;
}
if (eventType == XmlPullParser.END_DOCUMENT) break;
// We encounter a new keymap.
if (eventType == XmlPullParser.START_TAG && parser.getName().equals(TAG_KEYMAP)) {
keymap = new Keymap();
int attributeCount = parser.getAttributeCount();
for (int i = 0; i < attributeCount; ++i) {
switch (parser.getAttributeName(i)) {
case ATTR_LABEL:
label = parser.getAttributeValue(i);
break;
case ATTR_LATCHED_LABEL:
latchedLabel = parser.getAttributeValue(i);
break;
case ATTR_LOCKED_LABEL:
lockedLabel = parser.getAttributeValue(i);
break;
}
}
} else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(TAG_KEYMAP)
&& keymap != null) {
keymap.code = label;
keymap.latchedCode = latchedLabel;
keymap.lockedCode = lockedLabel;
mKeymaps.put(label, keymap);
}
// We got a new key.
if (eventType == XmlPullParser.START_TAG && parser.getName().equals(TAG_KEY)) {
key = new Key();
int attributeCount = parser.getAttributeCount();
for (int i = 0; i < attributeCount; ++i) {
if (parser.getAttributeName(i).equals(ATTR_CODE)) {
code = Integer.parseInt(parser.getAttributeValue(i));
}
}
} else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(TAG_KEY)
&& keymap != null) {
keymap.put(code, key);
}
// We encountered a base value.
if (eventType == XmlPullParser.START_TAG && parser.getName().equals(TAG_BASE)) {
int attributeCount = parser.getAttributeCount();
for (int i = 0; i < attributeCount; ++i) {
if (parser.getAttributeName(i).startsWith(ATTR_VALUE) && key != null) {
key.symbolsBase.add(parser.getAttributeValue(i));
}
}
}
// We encountered a shift value.
if (eventType == XmlPullParser.START_TAG && parser.getName().equals(TAG_SHIFT)) {
int attributeCount = parser.getAttributeCount();
for (int i = 0; i < attributeCount; ++i) {
if (parser.getAttributeName(i).startsWith(ATTR_VALUE) && key != null) {
key.symbolsShift.add(parser.getAttributeValue(i));
}
}
}
// We encountered an alt value.
if (eventType == XmlPullParser.START_TAG && parser.getName().equals(TAG_ALT)) {
int attributeCount = parser.getAttributeCount();
for (int i = 0; i < attributeCount; ++i) {
if (parser.getAttributeName(i).startsWith(ATTR_VALUE) && key != null) {
key.symbolsAlt.add(parser.getAttributeValue(i));
}
}
}
try {
parser.next();
} catch (XmlPullParserException | IOException e) {
break;
}
}
}
public ArrayList<String> getSymbols(int keyCode, MetaKeyManager metaKeyManager) {
ArrayList<String> alt = mCurrentKeymap.getSymbolsAlt(keyCode);
ArrayList<String> shift = mCurrentKeymap.getSymbolsShift(keyCode);
if (metaKeyManager.getAlt().isActive() && alt != null && !alt.isEmpty()) {
return alt;
}
if (metaKeyManager.getShift().isActive() && shift != null && !shift.isEmpty()) {
return shift;
}
return mCurrentKeymap.getSymbolsBase(keyCode);
}
public void adjustCurrentKeymap(List<String> selectedKeymaps) {
if (!selectedKeymaps.contains(mCurrentKeymap.code)) {
nextKeymap(selectedKeymaps);
}
}
public void nextKeymap(List<String> selectedKeymaps) {
if (!selectedKeymaps.isEmpty() && mCurrentKeymap != null) {
int index = selectedKeymaps.indexOf(mCurrentKeymap.code);
index++;
if (index == selectedKeymaps.size()) {
index = 0;
}
mCurrentKeymap = mKeymaps.get(selectedKeymaps.get(index));
} else {
mCurrentKeymap =
mKeymaps.get(mContext.getResources().getString(R.string.keymap_default));
}
}
public String getCurrentLabel() {
return mCurrentKeymap.code;
}
public String getCurrentLatchedLabel() {
return mCurrentKeymap.latchedCode;
}
public String getCurrentLockedLabel() {
return mCurrentKeymap.lockedCode;
}
static class Keymap {
private final static int INITIAL_KEYMAP_SIZE = 64; // Enough for just about any QWERTY.
private final HashMap<Integer, Key> mMap = new HashMap<>(INITIAL_KEYMAP_SIZE);
String code;
String latchedCode;
String lockedCode;
/**
* @noinspection ReturnOfNull
*/
public ArrayList<String> getSymbolsBase(int keyCode) {
Key key = mMap.get(keyCode);
return key == null ? null : key.symbolsBase;
}
/**
* @noinspection ReturnOfNull
*/
public ArrayList<String> getSymbolsAlt(int keyCode) {
Key key = mMap.get(keyCode);
return key == null ? null : key.symbolsAlt;
}
/**
* @noinspection ReturnOfNull
*/
public ArrayList<String> getSymbolsShift(int keyCode) {
Key key = mMap.get(keyCode);
return key == null ? null : key.symbolsShift;
}
public void put(Integer key, Key value) {
mMap.put(key, value);
}
}
static class Key {
private final static int INITIAL_SIZE = 6;
final ArrayList<String> symbolsBase = new ArrayList<>(INITIAL_SIZE);
final ArrayList<String> symbolsShift = new ArrayList<>(INITIAL_SIZE);
final ArrayList<String> symbolsAlt = new ArrayList<>(INITIAL_SIZE);
}
}
@@ -0,0 +1,65 @@
package eur.cfpifpsi.titanboard;
import android.view.KeyEvent;
public class MetaKey {
private static final long TOGGLE_DURATION = 400L;
private boolean mPressed;
private boolean mLatched;
private boolean mLocked;
private boolean mUsed;
private long mKeyUpTime;
public void onDown() {
mUsed = false;
mPressed = true;
// It's not true that mLocked is always true...
//noinspection ConstantValue
mLatched = mLocked ? mLocked : mLatched;
mLocked = false;
}
public void onUp(KeyEvent event) {
if (event.getEventTime() - mKeyUpTime < TOGGLE_DURATION) {
mLocked = true;
}
mKeyUpTime = event.getEventTime();
mPressed = false;
mLatched = !mLatched && !mLocked && !mUsed;
}
public void afterKeypress() {
if (mLatched) {
mLatched = false;
mUsed = false;
}
if (mPressed) {
mUsed = true;
}
}
public void resetState() {
mPressed = false;
mLatched = false;
mLocked = false;
mUsed = false;
}
public boolean isPressed() {
return mPressed;
}
public boolean isLatched() {
return mLatched;
}
public boolean isLocked() {
return mLocked;
}
public boolean isActive() {
return mPressed || mLocked || mLatched;
}
}
@@ -0,0 +1,91 @@
/*
* An input method for physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package eur.cfpifpsi.titanboard;
import android.os.Vibrator;
import android.view.KeyEvent;
public class MetaKeyManager {
private static final int TOGGLE_VIBRATION_TIME = 30;
public final MetaKey mShift = new MetaKey();
public final MetaKey mAlt = new MetaKey();
private final Vibrator mVibrator;
public MetaKeyManager(Vibrator vibrator) {
mVibrator = vibrator;
}
public boolean updateMetaStateDown(int keyCode) {
switch (keyCode) {
case KeyEvent.KEYCODE_ALT_LEFT:
case KeyEvent.KEYCODE_ALT_RIGHT:
mAlt.onDown();
return true;
case KeyEvent.KEYCODE_SHIFT_LEFT:
case KeyEvent.KEYCODE_SHIFT_RIGHT:
mShift.onDown();
return true;
default:
return false;
}
}
/**
* @noinspection FeatureEnvy
*/
public boolean updateMetaStateUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_ALT_LEFT:
case KeyEvent.KEYCODE_ALT_RIGHT:
mAlt.onUp(event);
if (mAlt.isLocked()) {
mVibrator.vibrate(TOGGLE_VIBRATION_TIME);
}
return true;
case KeyEvent.KEYCODE_SHIFT_LEFT:
case KeyEvent.KEYCODE_SHIFT_RIGHT:
mShift.onUp(event);
if (mShift.isLocked()) {
mVibrator.vibrate(TOGGLE_VIBRATION_TIME);
}
return true;
default:
return false;
}
}
public void adjustMetaStateAfterKeypress() {
mShift.afterKeypress();
mAlt.afterKeypress();
}
public void resetMetaKeyState() {
mShift.resetState();
mAlt.resetState();
}
public MetaKey getShift() {
return mShift;
}
public MetaKey getAlt() {
return mAlt;
}
}
@@ -1,6 +1,6 @@
/*
* An input method for the Unihertz Titan/physical keyboard phones
* Copyright (C) 2024 Emil Kosz
* An input method for physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,10 +14,9 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
package cfpi_fpsi.eu.titanboard;
package eur.cfpifpsi.titanboard;
import android.content.Context;
import android.content.SharedPreferences;
@@ -30,12 +29,12 @@ import java.util.Set;
/**
* @noinspection deprecation
*/
public class Settings implements SharedPreferences.OnSharedPreferenceChangeListener {
public class PreferenceHolder implements SharedPreferences.OnSharedPreferenceChangeListener {
private final Map<String, Object> mPreferenceValues;
private final Context mContext;
@SuppressWarnings("unchecked")
public Settings(Context context) {
@SuppressWarnings("unchecked") //NON-NLS
public PreferenceHolder(Context context) {
mContext = context;
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
PreferenceManager.setDefaultValues(mContext, R.xml.preferences, false);
@@ -56,36 +55,29 @@ public class Settings implements SharedPreferences.OnSharedPreferenceChangeListe
return value == null ? defaultValue : value;
}
public boolean isAutoCapsEnabled() {
return (boolean) getOrDefault("auto_caps",
mContext.getResources().getBoolean(R.bool.auto_caps_default));
}
public boolean isAutoPeriodsEnabled() {
return (boolean) getOrDefault("auto_periods",
mContext.getResources().getBoolean(R.bool.auto_periods_default));
}
public boolean isAutocorrectEnabled() {
return (boolean) getOrDefault("auto_correct",
mContext.getResources().getBoolean(R.bool.autocorrect_default));
}
public boolean isCyclingWithSpaceEnabled() {
return (boolean) getOrDefault("cycle_with_space",
mContext.getResources().getBoolean(R.bool.cycle_with_space_default));
public boolean isCycleManualOn() {
return (boolean) getOrDefault(mContext.getString(R.string.preferences_key_cycle_manual),
mContext.getResources().getBoolean(R.bool.cycle_manual_default));
}
public int getCycleSpeed() {
return Integer.parseInt((String) getOrDefault("cycle_speed",
mContext.getResources().getString(R.string.cycle_speed_default)));
return Integer.parseInt((String)
getOrDefault(mContext.getString(R.string.preferences_key_cycle_speed),
mContext.getString(R.string.cycle_speed_default)));
}
@SuppressWarnings("unchecked")
public int getClipboardSize() {
return Integer.parseInt((String)
getOrDefault(mContext.getString(R.string.preferences_key_clipboard_size),
mContext.getString(R.string.clipboard_size_default)));
}
@SuppressWarnings("unchecked") //NON-NLS
public ArrayList<String> getSelectedKeymaps() {
Set<String> selectedKeymaps = (Set<String>)
getOrDefault("selected_keymaps",
mContext.getResources().getStringArray(R.array.selected_keymap_defaults));
getOrDefault(mContext.getString(R.string.preferences_key_keymaps),
mContext.getResources()
.getStringArray(R.array.preferences_keymap_defaults));
return new ArrayList<>(selectedKeymaps);
}
}
@@ -1,6 +1,6 @@
/*
* An input method for the Unihertz Titan/physical keyboard phones
* Copyright (C) 2024 Emil Kosz
* An input method for physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,16 +14,13 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
package cfpi_fpsi.eu.titanboard;
package eur.cfpifpsi.titanboard;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import java.util.Objects;
/**
* @noinspection deprecation
*/
@@ -32,6 +29,5 @@ public class SettingsActivity extends PreferenceActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
Objects.requireNonNull(getActionBar()).setDisplayHomeAsUpEnabled(true);
}
}
@@ -0,0 +1,275 @@
/*
* An input method for physical keyboard phones
* Copyright (C) 2024 Emil Kosz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package eur.cfpifpsi.titanboard;
import android.annotation.SuppressLint;
import android.inputmethodservice.InputMethodService;
import android.os.Handler;
import android.os.Looper;
import android.os.Vibrator;
import android.text.InputType;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import java.util.ArrayList;
// TODO: Implement device recognition and a keymap picking based on it.
public class TitanboardIME extends InputMethodService {
public MetaKeyManager mMetaKeyManager;
public KeymapManager mKeymapManager;
public PreferenceHolder mPreferenceHolder;
public ClipManager mClipManager;
public InputView mInputView;
public Vibrator mVibrator;
int mCurrentCursorPosition;
Handler mHandler;
private SymbolAutoCycler mSymbolAutoCycler;
private SymbolManualCycler mSymbolManualCycler;
private FinishCyclingRunnable mFinishCyclingRunnable;
private int mLastSymbolKeyCode;
@Override
public void onCreate() {
super.onCreate();
mPreferenceHolder = new PreferenceHolder(this);
mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
mMetaKeyManager = new MetaKeyManager(mVibrator);
mKeymapManager = new KeymapManager(this);
mClipManager = new ClipManager(this);
mHandler = new Handler(Looper.getMainLooper());
mSymbolAutoCycler = new SymbolAutoCycler();
mSymbolManualCycler = new SymbolManualCycler();
mFinishCyclingRunnable = new FinishCyclingRunnable();
mKeymapManager.nextKeymap(mPreferenceHolder.getSelectedKeymaps());
}
@SuppressLint("InflateParams")
@Override
public void onInitializeInterface() {
mInputView = (InputView) getLayoutInflater().inflate(R.layout.input, null);
mInputView.updateStateText();
mInputView.setSymbolsVisible(false);
}
@Override
public View onCreateInputView() {
return mInputView;
}
@Override
public boolean onEvaluateFullscreenMode() {
// This is to override the default behaviour, which seems to do more than detect landscape
// mode.
return false;
}
/**
* @noinspection FeatureEnvy
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (mMetaKeyManager.updateMetaStateDown(keyCode)) {
mInputView.updateStateText();
return true;
}
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (isInputViewShown()) {
requestHideSelf(0);
return true;
}
return false;
}
// Workaround for default Android behaviour that pisses people off.
if (keyCode == KeyEvent.KEYCODE_DEL && (event.isAltPressed() || event.isShiftPressed())) {
return true;
}
if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_ENTER) {
mMetaKeyManager.adjustMetaStateAfterKeypress();
mInputView.updateStateText();
return false;
}
ArrayList<String> symbols = mKeymapManager.getSymbols(keyCode, mMetaKeyManager);
InputConnection conn = getCurrentInputConnection();
EditorInfo info = getCurrentInputEditorInfo();
if (symbols == null || conn == null || info == null) {
return false;
}
if (info.inputType == InputType.TYPE_NULL) {
return false;
}
if (event.getRepeatCount() == 0 && !symbols.isEmpty()) {
mMetaKeyManager.adjustMetaStateAfterKeypress();
mInputView.updateStateText();
if (mPreferenceHolder.isCycleManualOn()) {
boolean isCycling = mHandler.hasMessages(0);
if (isCycling && keyCode == mLastSymbolKeyCode
&& mSymbolManualCycler.getList().size() > 1) {
mSymbolManualCycler.run();
} else {
mFinishCyclingRunnable.run();
conn.commitText(symbols.get(0), 1);
mSymbolManualCycler.prepare(symbols);
}
mHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(mFinishCyclingRunnable, mPreferenceHolder.getCycleSpeed());
mLastSymbolKeyCode = keyCode;
} else {
conn.commitText(symbols.get(0), 1);
if (symbols.size() > 1) {
mSymbolAutoCycler.prepare(symbols);
mHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(mSymbolAutoCycler, mPreferenceHolder.getCycleSpeed());
}
}
}
return true;
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
// If manual cycling is on, all this is done using a Runnable after some timeout.
if (!mPreferenceHolder.isCycleManualOn()) {
mFinishCyclingRunnable.run();
}
if (mMetaKeyManager.updateMetaStateUp(keyCode, event)) {
mInputView.updateStateText();
return true;
}
return false;
}
@Override
public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd,
int candidatesStart, int candidatesEnd) {
mCurrentCursorPosition = newSelStart;
}
@Override
public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
// getCharacterBounds() --- API 21 (Lollipop)
// getInsertionMarkerTop() -- API 21 (Lollipop)
}
@Override
public void onStartInput(EditorInfo attribute, boolean restarting) {
super.onStartInput(attribute, restarting);
mKeymapManager.adjustCurrentKeymap(mPreferenceHolder.getSelectedKeymaps());
mInputView.updateStateText();
// Soon™
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// getCurrentInputConnection().requestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR);
// }
}
@Override
public void onFinishInput() {
mMetaKeyManager.resetMetaKeyState();
mInputView.mClipboardPopup.dismiss();
}
// Cyclers & runnables
class FinishCyclingRunnable implements Runnable {
@Override
public void run() {
InputConnection conn = getCurrentInputConnection();
if (conn != null) {
conn.finishComposingText();
}
mHandler.removeCallbacksAndMessages(null);
mInputView.setSymbolsVisible(false);
}
}
class SymbolManualCycler extends Cycler {
@Override
public void onCycle() {
mVibrator.vibrate(10);
mInputView.setSelectedSymbol(getIndex());
InputConnection conn = getCurrentInputConnection();
if (conn != null) {
conn.setComposingText(getCurrentElement().toString(), 1);
}
}
@SuppressWarnings("unchecked") //NON-NLS
@Override
public void onFirstCycle() {
mInputView.setSymbolsVisible(true);
mInputView.setSymbols((ArrayList<String>) getList());
InputConnection conn = getCurrentInputConnection();
if (conn != null) {
conn.setSelection(mCurrentCursorPosition - getElementAt(0).toString().length(),
mCurrentCursorPosition);
}
}
}
class SymbolAutoCycler extends Cycler {
@Override
public void onCycle() {
mVibrator.vibrate(10);
mInputView.setSelectedSymbol(getIndex());
InputConnection conn = getCurrentInputConnection();
if (conn != null) {
conn.setComposingText(getCurrentElement().toString(), 1);
}
mHandler.postDelayed(this, mPreferenceHolder.getCycleSpeed());
}
@SuppressWarnings("unchecked") //NON-NLS
@Override
public void onFirstCycle() {
mInputView.setSymbolsVisible(true);
mInputView.setSymbols((ArrayList<String>) getList());
InputConnection conn = getCurrentInputConnection();
if (conn != null) {
conn.setSelection(mCurrentCursorPosition - getElementAt(0).toString().length(),
mCurrentCursorPosition);
}
}
}
}
+11 -8
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for the Unihertz Titan/physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@@ -14,20 +14,23 @@
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
~
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item app:state_toggled="true">
<shape android:shape="rectangle">
<solid android:color="@color/button_toggled" />
</shape>
</item>
<item android:state_pressed="false">
<shape android:shape="rectangle">
<solid android:color="#333" />
<corners android:radius="8dp" />
<solid android:color="@android:color/transparent" />
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#555" />
<corners android:radius="8dp" />
<solid android:color="@color/button_active" />
</shape>
</item>
</selector>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_state" android:state_pressed="false" />
<item android:state_pressed="true">
<layer-list>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/button_active" />
</shape>
</item>
<item android:drawable="@drawable/ic_state" />
</layer-list>
</item>
</selector>
+82
View File
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background -->
<item>
<shape android:shape="rectangle">
<size
android:width="128px"
android:height="128px" />
<solid android:color="#333" />
</shape>
</item>
<!-- Helper -->
<!-- <item android:top="24px"-->
<!-- android:bottom="24px"-->
<!-- android:left="24px"-->
<!-- android:right="24px">-->
<!-- <shape android:shape="rectangle">-->
<!-- <solid android:color="@android:color/darker_gray" />-->
<!-- </shape>-->
<!-- </item>-->
<!-- Top -->
<item
android:bottom="90px"
android:left="24px"
android:right="24px"
android:top="24px">
<shape android:shape="rectangle">
<solid android:color="@color/text_color" />
<corners android:radius="36px" />
</shape>
</item>
<!-- Stem of the T -->
<item
android:bottom="24px"
android:left="40px"
android:right="72px"
android:top="24px">
<shape android:shape="rectangle">
<solid android:color="@color/text_color" />
<corners android:radius="36px" />
</shape>
</item>
<!-- Stem of the I -->
<item
android:bottom="24px"
android:left="72px"
android:right="40px"
android:top="24px">
<shape android:shape="rectangle">
<solid android:color="@color/text_color" />
<corners android:radius="36px" />
</shape>
</item>
<!-- Bottom of the I -->
<item
android:bottom="24px"
android:left="60px"
android:right="29px"
android:top="90px">
<shape android:shape="rectangle">
<solid android:color="@color/text_color" />
<corners android:radius="36px" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background -->
<item>
<shape android:shape="oval">
<size
android:width="128px"
android:height="128px" />
<solid android:color="#333" />
</shape>
</item>
<!-- Helper -->
<!-- <item android:top="24px"-->
<!-- android:bottom="24px"-->
<!-- android:left="24px"-->
<!-- android:right="24px">-->
<!-- <shape android:shape="rectangle">-->
<!-- <solid android:color="@android:color/darker_gray" />-->
<!-- </shape>-->
<!-- </item>-->
<!-- Top -->
<item
android:bottom="90px"
android:left="24px"
android:right="24px"
android:top="24px">
<shape android:shape="rectangle">
<solid android:color="@color/text_color" />
<corners android:radius="36px" />
</shape>
</item>
<!-- Stem of the T -->
<item
android:bottom="24px"
android:left="40px"
android:right="72px"
android:top="24px">
<shape android:shape="rectangle">
<solid android:color="@color/text_color" />
<corners android:radius="36px" />
</shape>
</item>
<!-- Stem of the I -->
<item
android:bottom="24px"
android:left="72px"
android:right="40px"
android:top="24px">
<shape android:shape="rectangle">
<solid android:color="@color/text_color" />
<corners android:radius="36px" />
</shape>
</item>
<!-- Bottom of the I -->
<item
android:bottom="24px"
android:left="60px"
android:right="29px"
android:top="90px">
<shape android:shape="rectangle">
<solid android:color="@color/text_color" />
<corners android:radius="36px" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- <item android:top="11dp"-->
<!-- android:bottom="11dp"-->
<!-- android:right="14dp"-->
<!-- android:left="14dp">-->
<!-- <shape android:shape="rectangle">-->
<!-- <solid android:color="@android:color/darker_gray" />-->
<!-- </shape>-->
<!-- </item>-->
<!-- Main board -->
<item
android:bottom="11dp"
android:left="14dp"
android:right="14dp"
android:top="12.5dp">
<shape android:shape="rectangle">
<stroke
android:width="2dp"
android:color="@color/text_color" />
<corners android:radius="2dp" />
</shape>
</item>
<!-- The clip -->
<item
android:bottom="32dp"
android:left="20dp"
android:right="20dp"
android:top="11dp">
<shape android:shape="rectangle">
<solid android:color="@color/text_color" />
<corners android:radius="2dp" />
</shape>
</item>
<!-- Squiggles -->
<item
android:bottom="7dp"
android:left="18dp"
android:right="18dp">
<shape android:shape="line">
<stroke
android:width="2dp"
android:color="@color/text_color" />
</shape>
</item>
<item
android:left="18dp"
android:right="18dp"
android:top="2dp">
<shape android:shape="line">
<stroke
android:width="2dp"
android:color="@color/text_color" />
</shape>
</item>
<item
android:left="18dp"
android:right="22dp"
android:top="11dp">
<shape android:shape="line">
<stroke
android:width="2dp"
android:color="@color/text_color" />
</shape>
</item>
</layer-list>
+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="11dp"
android:left="9dp"
android:right="9dp"
android:top="11dp">
<shape android:shape="rectangle">
<solid android:color="@color/text_color" />
<corners android:radius="2dp" />
</shape>
</item>
</layer-list>
+83
View File
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Icons are 32x32 dp, leaving 8dp of padding on each side -->
<!-- It is tempting to use insets here, but they lead to unexpected behaviour. -->
<!-- Helper: so that the icon is relatively proportional -->
<!-- <item android:top="11dp"-->
<!-- android:bottom="11dp"-->
<!-- android:right="14dp"-->
<!-- android:left="14dp">-->
<!-- <shape android:shape="rectangle">-->
<!-- <solid android:color="@android:color/darker_gray" />-->
<!-- </shape>-->
<!-- </item>-->
<!-- Handle -->
<item
android:bottom="31dp"
android:left="19dp"
android:right="19dp"
android:top="11dp">
<shape android:shape="rectangle">
<stroke
android:width="2dp"
android:color="@color/danger_text_color" />
<corners android:radius="8dp" />
</shape>
</item>
<!-- Lid -->
<item
android:bottom="16dp"
android:left="13dp"
android:right="13dp">
<shape android:shape="line">
<stroke
android:width="2dp"
android:color="@color/danger_text_color" />
</shape>
</item>
<!-- Bin -->
<item
android:bottom="11dp"
android:left="15dp"
android:right="15dp"
android:top="15dp">
<shape android:shape="rectangle">
<stroke
android:width="2dp"
android:color="@color/danger_text_color" />
<corners
android:bottomLeftRadius="4dp"
android:bottomRightRadius="4dp" />
</shape>
</item>
<!-- Stripes -->
<item
android:bottom="11dp"
android:left="20dp"
android:right="20dp"
android:top="15dp">
<shape android:shape="rectangle">
<stroke
android:width="2dp"
android:color="@color/danger_text_color" />
</shape>
</item>
</layer-list>
-19
View File
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000"
android:viewportWidth="98"
android:viewportHeight="200.67188">
<group
android:scaleX="0.44929066"
android:scaleY="0.92"
android:translateX="26.984758"
android:translateY="8.0268755">
<group android:translateY="158.69531">
<path
android:fillColor="#000000"
android:pathData="M95.765625,-88.8125Q90.5625,-88.8125,79.734375,-89.65625Q69.1875,-90.421875,63.703125,-90.359375L58.71875,-90.359375Q58.921875,-80.65625,60.609375,-58.859375Q62.15625,-38.53125,62.15625,-27.28125Q62.15625,-24.828125,62.640625,-19.828125Q63.140625,-14.84375,63.140625,-12.3125Q63.140625,-7.53125,61.59375,-4.078125Q59.625,0.5625,55.484375,0.5625Q52.671875,0.5625,50.421875,-1.40625Q48.171875,-3.375,48.171875,-6.46875Q48.171875,-7.53125,48.515625,-9.640625Q48.875,-11.75,48.875,-12.796875Q48.875,-16.25,48.40625,-23.140625Q47.953125,-30.03125,47.953125,-33.546875Q47.953125,-43.59375,46.34375,-61.8125Q44.65625,-81.5,44.4375,-90.078125L38.046875,-90Q22.640625,-90,13.859375,-92.25Q8.15625,-93.734375,8.15625,-99.21875Q8.15625,-102.09375,9.984375,-104.28125Q12.09375,-106.734375,15.40625,-106.53125Q17.859375,-106.390625,26.65625,-105.265625Q33.6875,-104.421875,38.046875,-104.421875Q42.265625,-104.421875,50.84375,-104.59375Q59.421875,-104.765625,63.640625,-104.765625Q69.046875,-104.765625,79.703125,-103.984375Q90.359375,-103.21875,95.765625,-103.21875Q98.796875,-103.21875,100.828125,-101.140625Q102.875,-99.078125,102.875,-95.984375Q102.875,-92.953125,100.828125,-90.875Q98.796875,-88.8125,95.765625,-88.8125Z" />
</group>
</group>
</vector>
+49
View File
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/paste_button"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/button"
android:ellipsize="end"
android:gravity="center_vertical"
android:paddingLeft="14dp"
android:paddingTop="@dimen/default_space"
android:paddingRight="14dp"
android:paddingBottom="@dimen/default_space"
android:singleLine="true"
android:text="@string/clip_default_text"
android:textColor="@color/text_color"
android:textSize="@dimen/default_text_size" />
<ImageButton
android:id="@+id/button_delete"
android:layout_width="@dimen/button_size"
android:layout_height="@dimen/button_size"
android:background="@drawable/button"
android:contentDescription="@string/delete_button_description"
android:src="@drawable/ic_trashcan"
tools:ignore="UnusedAttribute" />
</LinearLayout>
+32
View File
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/button_toggled"
android:scrollbarThumbVertical="@color/text_color"
tools:ignore="Overdraw">
<LinearLayout
android:id="@+id/clip_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView>
+54 -58
View File
@@ -1,71 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<cfpi_fpsi.eu.titanboard.InputView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/InputViewBackground"
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<eur.cfpifpsi.titanboard.InputView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom">
android:layout_gravity="bottom"
android:background="@color/background"
tools:ignore="Overdraw">
<HorizontalScrollView
android:id="@+id/symbol_list_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignTop="@id/input_state"
android:layout_alignBottom="@id/input_state"
android:layout_toStartOf="@id/input_state">
android:layout_alignTop="@id/clipboard_button"
android:layout_alignBottom="@id/clipboard_button"
android:layout_toStartOf="@+id/clipboard_button"
android:layout_toLeftOf="@id/clipboard_button"
android:scrollbarThumbHorizontal="@color/text_color">
<LinearLayout
android:id="@+id/multi_list"
android:id="@+id/symbol_list"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
style="@style/InputViewSymbol"
android:layout_height="wrap_content" />
<TextView
style="@style/InputViewSymbol"
android:layout_height="wrap_content" />
<TextView
style="@style/InputViewSymbol"
android:layout_height="wrap_content" />
<TextView
style="@style/InputViewSymbol"
android:layout_height="wrap_content" />
<TextView
style="@style/InputViewSymbol"
android:layout_height="wrap_content" />
<TextView
style="@style/InputViewSymbol"
android:layout_height="wrap_content" />
<TextView
style="@style/InputViewSymbol"
android:layout_height="wrap_content" />
<TextView
style="@style/InputViewSymbol"
android:layout_height="wrap_content" />
<TextView
style="@style/InputViewSymbol"
android:layout_height="wrap_content" />
<TextView
style="@style/InputViewSymbol"
android:layout_height="wrap_content" />
</LinearLayout>
android:orientation="horizontal" />
</HorizontalScrollView>
<Button
android:id="@+id/input_state"
style="@style/InputViewButton"
android:layout_alignParentEnd="true"
android:layout_marginStart="8dp"
android:text="@string/inputview_default_state" />
<ImageButton
android:id="@+id/clipboard_button"
android:layout_width="@dimen/button_size"
android:layout_height="@dimen/button_size"
android:layout_toStartOf="@id/state_button"
android:layout_toLeftOf="@id/state_button"
android:background="@drawable/button"
android:contentDescription="@string/clipboard_button_description"
android:src="@drawable/ic_clipboard"
tools:ignore="UnusedAttribute" />
</cfpi_fpsi.eu.titanboard.InputView>
<Button
android:id="@+id/state_button"
android:layout_width="@dimen/button_size"
android:layout_height="@dimen/button_size"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="@drawable/button_state"
android:text="@string/state_button_default"
android:textAllCaps="false"
android:textColor="@color/background"
android:textSize="@dimen/default_text_size" />
</eur.cfpifpsi.titanboard.InputView>
+27
View File
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/button"
android:gravity="center"
android:textColor="@color/text_color"
android:textSize="@dimen/symbol_text_size">
</TextView>
-56
View File
@@ -1,56 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for the Unihertz Titan/physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
~
-->
<cfpi_fpsi.eu.titanboard.SymbolsView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageView"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_below="@id/textView"
android:src="@drawable/triangle" />
<TextView
android:id="@+id/textView"
style="@style/SymbolsViewSymbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:text="A" />
<TextView
android:id="@+id/textView2"
style="@style/SymbolsViewSymbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/textView"
android:text="B" />
<TextView
android:id="@+id/textView3"
style="@style/SymbolsViewSymbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/textView2"
android:text="C" />
</cfpi_fpsi.eu.titanboard.SymbolsView>
+34 -11
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for the Unihertz Titan/physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@@ -14,32 +14,39 @@
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
~
-->
<resources>
<string-array name="available_keymap_labels">
<string-array name="preferences_keymap_labels">
<item>English</item>
<item>Russian (Phonetic)</item>
<item>German</item>
<item>French</item>
<item>Italian</item>
<item>Spanish</item>
<item>Polish</item>
<item>Greek</item>
<item>Russian (Phonetic)</item>
<item>Greek (diacritics under Q)</item>
<item>Arabic (Phonetic)</item>
</string-array>
<string-array name="available_keymaps">
<string-array name="preferences_keymaps">
<item>en</item>
<item>ru</item>
<item>de</item>
<item>fr</item>
<item>it</item>
<item>es</item>
<item>pl</item>
<item>ru</item>
<item>el</item>
<item>ar</item>
</string-array>
<string-array name="selected_keymap_defaults">
<string-array name="preferences_keymap_defaults">
<item>en</item>
<item>ru</item>
</string-array>
<string-array name="cycle_speed_labels">
<string-array name="preferences_cycle_speed_labels">
<item>200 ms</item>
<item>300 ms</item>
<item>400 ms</item>
@@ -48,7 +55,7 @@
<item>1000 ms</item>
</string-array>
<string-array name="cycle_speeds">
<string-array name="preferences_cycle_speeds">
<item>200</item>
<item>300</item>
<item>400</item>
@@ -56,4 +63,20 @@
<item>750</item>
<item>1000</item>
</string-array>
<string-array name="preferences_clipboard_size_labels">
<item>3 items</item>
<item>5 items</item>
<item>10 items</item>
<item>20 items</item>
<item>30 items</item>
</string-array>
<string-array name="preferences_clipboard_sizes">
<item>3</item>
<item>5</item>
<item>10</item>
<item>20</item>
<item>30</item>
</string-array>
</resources>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for the Unihertz Titan/physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@@ -14,14 +14,8 @@
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
~
-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="45"
android:pivotX="100%"
android:pivotY="-50%">
<shape android:shape="rectangle">
<solid android:color="#333" />
</shape>
</rotate>
<resources>
<attr name="state_toggled" format="boolean" />
</resources>
+3 -7
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for the Unihertz Titan/physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@@ -14,12 +14,8 @@
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
~
-->
<resources>
<bool name="auto_caps_default">true</bool>
<bool name="auto_periods_default">true</bool>
<bool name="autocorrect_default">false</bool>
<bool name="cycle_with_space_default">false</bool>
<bool name="cycle_manual_default">false</bool>
</resources>
+25
View File
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<color name="background">#222</color>
<color name="button_toggled">#555</color>
<color name="button_active">#666</color>
<color name="text_color">#EEE</color>
<color name="danger_text_color">#FF0000</color>
</resources>
+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<dimen name="default_space">8dp</dimen>
<dimen name="button_size">48dp</dimen>
<dimen name="symbol_width">40dp</dimen>
<dimen name="clipboard_popup_width">256dp</dimen>
<dimen name="clipboard_popup_height">256dp</dimen>
<dimen name="default_text_size">16sp</dimen>
<dimen name="symbol_text_size">18sp</dimen>
</resources>
+49 -15
View File
@@ -1,21 +1,55 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">Titanboard</string>
<string name="ime_label">Titanboard</string>
<string name="preferences_label">Titanboard preferences</string>
<string name="preferences_general_settings">General</string>
<string name="preferences_auto_caps">Automatic capitalization</string>
<string name="preferences_auto_periods">Automatic periods</string>
<string name="preferences_auto_correct">Autocorrect</string>
<string name="preferences_editing_settings">Editing and keymaps</string>
<string name="preferences_cycle_speed">Cycling speed</string>
<string name="preferences_cycle_with_space">Cycle symbols with the space key</string>
<string name="preferences_keymaps">Keymaps</string>
<string name="inputview_default_state">\?\?</string>
<string name="inputview_symbols_latched_state">#?</string>
<string name="inputview_symbols_locked_state">#!</string>
<string name="preferences_name">Titanboard preferences</string>
<string name="keymap_default">en</string>
<string name="cycle_speed_default">500</string>
<string name="clipboard_size_default">5</string>
<string name="state_button_default">\??</string>
<string name="state_button_alt_locked">#!</string>
<string name="state_button_alt_latched">#?</string>
<string name="delete_button_description">Delete clipboard item</string>
<string name="clipboard_button_description">
Open clipboard or paste first item on long press
</string>
<string name="clip_default_text">Clip</string>
<string name="preferences_label_cycle_manual">
Cycle symbols by consecutively pressing a key
</string>
<string name="preferences_label_cycle_speed">Symbol cycling speed/timeout</string>
<string name="preferences_label_clipboard_size">Clipboard size</string>
<string name="preferences_label_keymaps">Languages</string>
<string name="preferences_label_copyright_info">
Copyleft 🄯 Emil Kosz, 2024. License: GPLv3
</string>
<string name="preferences_summary_cycle_manual">
Overrides the default behaviour of long pressing to cycle
</string>
<string name="preferences_key_cycle_manual">cycle_manual</string>
<string name="preferences_key_keymaps">selected_keymaps</string>
<string name="preferences_key_cycle_speed">cycle_speed</string>
<string name="preferences_key_clipboard_size">clipboard_size</string>
</resources>
-44
View File
@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="InputViewBackground">
<item name="android:background">#222</item>
<item name="android:padding">8dp</item>
</style>
<style name="InputViewButton">
<item name="android:background">@drawable/button</item>
<item name="android:textColor">#AAA</item>
<item name="android:textSize">18sp</item>
<item name="android:textAlignment">center</item>
<item name="android:gravity">center_vertical</item>
<item name="android:layout_width">48dp</item>
<item name="android:layout_height">48dp</item>
<item name="android:clickable">true</item>
</style>
<style name="InputViewSymbol">
<item name="android:textColor">#AAA</item>
<item name="android:textSize">18sp</item>
<item name="android:textAlignment">center</item>
<item name="android:layout_width">32dp</item>
<item name="android:layout_height">48dp</item>
<item name="android:layout_marginStart">8dp</item>
<item name="android:layout_weight">0</item>
<item name="android:layout_gravity">center_vertical</item>
</style>
<style name="InputViewSymbolSelected" parent="InputViewSymbol">
<item name="android:textColor">#DDD</item>
<item name="android:textStyle">bold</item>
</style>
<style name="SymbolsViewSymbol">
<item name="android:background">#333</item>
<item name="android:textColor">#AAA</item>
<item name="android:textSize">16sp</item>
<item name="android:textAlignment">center</item>
<item name="android:padding">8dp</item>
<item name="android:layout_gravity">center_vertical</item>
</style>
</resources>
File diff suppressed because it is too large Load Diff
+27 -4
View File
@@ -1,9 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for the Unihertz Titan/physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
~
-->
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="cfpi_fpsi.eu.titanboard.SettingsActivity"
android:supportsSwitchingToNextInputMethod="false">
xmlns:tools="http://schemas.android.com/tools"
android:settingsActivity="eur.cfpifpsi.titanboard.SettingsActivity">
<!-- Needed for higher Android version so it can be the only used input method.
None of these subtypes are actually used. -->
<subtype
android:imeSubtypeMode="keyboard"
tools:targetApi="honeycomb" />
<subtype
android:imeSubtypeMode="keyboard"
android:isAsciiCapable="true"
android:label="Default" />
tools:targetApi="kitkat" />
</input-method>
+27 -35
View File
@@ -19,39 +19,31 @@
<!--suppress DeprecatedClassUsageInspection -->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/preferences_general_settings">
<SwitchPreference
android:defaultValue="@bool/auto_caps_default"
android:key="auto_caps"
android:title="@string/preferences_auto_caps" />
<SwitchPreference
android:defaultValue="@bool/auto_periods_default"
android:key="auto_periods"
android:title="@string/preferences_auto_periods" />
<SwitchPreference
android:defaultValue="@bool/autocorrect_default"
android:enabled="false"
android:key="autocorrect"
android:title="@string/preferences_auto_correct" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/preferences_editing_settings">
<MultiSelectListPreference
android:defaultValue="@array/selected_keymap_defaults"
android:entries="@array/available_keymap_labels"
android:entryValues="@array/available_keymaps"
android:key="selected_keymaps"
android:title="@string/preferences_keymaps" />
<SwitchPreference
android:defaultValue="@bool/cycle_with_space_default"
android:key="cycle_with_space"
android:title="@string/preferences_cycle_with_space" />
<ListPreference
android:defaultValue="@string/cycle_speed_default"
android:entries="@array/cycle_speed_labels"
android:entryValues="@array/cycle_speeds"
android:key="cycle_speed"
android:title="@string/preferences_cycle_speed" />
</PreferenceCategory>
<SwitchPreference
android:defaultValue="@bool/cycle_manual_default"
android:key="@string/preferences_key_cycle_manual"
android:summary="@string/preferences_summary_cycle_manual"
android:title="@string/preferences_label_cycle_manual" />
<ListPreference
android:defaultValue="@string/cycle_speed_default"
android:disableDependentsState="true"
android:entries="@array/preferences_cycle_speed_labels"
android:entryValues="@array/preferences_cycle_speeds"
android:key="@string/preferences_key_cycle_speed"
android:title="@string/preferences_label_cycle_speed" />
<ListPreference
android:defaultValue="@string/clipboard_size_default"
android:entries="@array/preferences_clipboard_size_labels"
android:entryValues="@array/preferences_clipboard_sizes"
android:key="@string/preferences_key_clipboard_size"
android:title="@string/preferences_label_clipboard_size" />
<MultiSelectListPreference
android:defaultValue="@array/preferences_keymap_defaults"
android:entries="@array/preferences_keymap_labels"
android:entryValues="@array/preferences_keymaps"
android:key="@string/preferences_key_keymaps"
android:title="@string/preferences_label_keymaps" />
<Preference
android:selectable="false"
android:summary="@string/preferences_label_copyright_info" />
</PreferenceScreen>
+1 -1
View File
@@ -1,4 +1,4 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.application) apply false
}
+1 -4
View File
@@ -1,8 +1,5 @@
[versions]
#noinspection AndroidGradlePluginVersion
agp = "8.4.1"
[libraries]
agp = "8.4.2"
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
+4 -4
View File
@@ -2,9 +2,9 @@ pluginManagement {
repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
includeGroupByRegex('com\\.android.*')
includeGroupByRegex('com\\.google.*')
includeGroupByRegex('androidx.*')
}
}
mavenCentral()
@@ -19,5 +19,5 @@ dependencyResolutionManagement {
}
}
rootProject.name = "Titanboard"
rootProject.name = 'Titanboard'
include ':app'