├── .gitignore ├── LICENSE.md ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── leankeykeyboard_logo_small.png ├── leankeykeyboard_screenshot_01.png ├── leankeykeyboard_screenshot_02.png ├── leankeykeyboard_screenshot_03.png ├── screen4.png └── screen5.png ├── leankeykeyboard ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── liskovsoft │ │ └── leankeykeyboard │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── liskovsoft │ │ │ └── leankeyboard │ │ │ ├── activity │ │ │ ├── PermissionsActivity.java │ │ │ └── settings │ │ │ │ ├── KbLayoutActivity.java │ │ │ │ ├── KbSettingsActivity.java │ │ │ │ └── KbSettingsActivity2.java │ │ │ ├── addons │ │ │ ├── keyboards │ │ │ │ ├── KeyboardBuilder.java │ │ │ │ ├── KeyboardFactory.java │ │ │ │ ├── KeyboardInfo.java │ │ │ │ ├── KeyboardManager.java │ │ │ │ ├── KeyboardStateManager.java │ │ │ │ ├── extkeyboards │ │ │ │ │ ├── addons │ │ │ │ │ │ ├── AddOn.java │ │ │ │ │ │ ├── AddOnImpl.java │ │ │ │ │ │ ├── AddOnsFactory.java │ │ │ │ │ │ └── Support.java │ │ │ │ │ ├── keyboards │ │ │ │ │ │ ├── ApkKeyboardAddOnAndBuilder.java │ │ │ │ │ │ └── ApkLangKeyboardFactory.java │ │ │ │ │ └── utils │ │ │ │ │ │ ├── log │ │ │ │ │ │ ├── BuildConfig.java │ │ │ │ │ │ ├── LogCatLogProvider.java │ │ │ │ │ │ ├── LogProvider.java │ │ │ │ │ │ ├── Logger.java │ │ │ │ │ │ └── NullLogProvider.java │ │ │ │ │ │ └── xml │ │ │ │ │ │ ├── XmlUtils.java │ │ │ │ │ │ └── XmlWriter.java │ │ │ │ └── intkeyboards │ │ │ │ │ ├── CheckedSource.java │ │ │ │ │ ├── KeyboardInfoAdapter.java │ │ │ │ │ ├── ResKeyboardFactory.java │ │ │ │ │ └── ResKeyboardInfo.java │ │ │ ├── resize │ │ │ │ ├── KeyboardWrapper.java │ │ │ │ └── ResizeableLeanbackKeyboardView.java │ │ │ ├── theme │ │ │ │ └── ThemeManager.java │ │ │ └── voice │ │ │ │ ├── ActivityListener.java │ │ │ │ ├── RecognizerCallback.java │ │ │ │ ├── RecognizerIntentActivity.java │ │ │ │ ├── RecognizerIntentWrapper.java │ │ │ │ ├── SearchCallback.java │ │ │ │ ├── SystemVoiceDialog.java │ │ │ │ ├── VoiceDialog.java │ │ │ │ ├── VoiceOverlayDialog.java │ │ │ │ └── VoiceSearchBridge.java │ │ │ ├── fragments │ │ │ └── settings │ │ │ │ ├── BaseSettingsFragment.java │ │ │ │ ├── KbLayoutFragment.java │ │ │ │ ├── KbSettingsFragment.java │ │ │ │ ├── KbThemeFragment.java │ │ │ │ └── MiscFragment.java │ │ │ ├── helpers │ │ │ ├── AppInfoHelpers.java │ │ │ ├── Helpers.java │ │ │ ├── MessageHelpers.java │ │ │ └── PermissionHelpers.java │ │ │ ├── ime │ │ │ ├── EventLogTags.java │ │ │ ├── KeyMapperImeService.java │ │ │ ├── LeanbackImeService.java │ │ │ ├── LeanbackKeyboardContainer.java │ │ │ ├── LeanbackKeyboardController.java │ │ │ ├── LeanbackKeyboardView.java │ │ │ ├── LeanbackLocales.java │ │ │ ├── LeanbackSuggestionsFactory.java │ │ │ ├── LeanbackUtils.java │ │ │ ├── pano │ │ │ │ └── util │ │ │ │ │ ├── TouchNavMotionTracker.java │ │ │ │ │ └── TouchNavSpaceTracker.java │ │ │ └── voice │ │ │ │ ├── BitmapSoundLevelView.java │ │ │ │ ├── RecognizerView.java │ │ │ │ └── SpeechLevelSource.java │ │ │ ├── receiver │ │ │ ├── RestartServiceReceiver.java │ │ │ └── TextUpdateReceiver.java │ │ │ ├── utils │ │ │ ├── LangUpdater.java │ │ │ ├── LeanKeyPreferences.java │ │ │ ├── LocaleScript.java │ │ │ ├── LocaleUtility.java │ │ │ └── TextDrawable.java │ │ │ └── widgets │ │ │ └── DialogTitle.java │ └── res │ │ ├── drawable-hdpi-v4 │ │ ├── ic_voice_available.png │ │ ├── ic_voice_focus.png │ │ ├── ic_voice_off.png │ │ ├── ic_voice_recording.png │ │ ├── key_selector.9.png │ │ ├── touch_selector.9.png │ │ ├── vs_reactive_dark.png │ │ └── vs_reactive_light.png │ │ ├── drawable-mdpi-v4 │ │ ├── ic_voice_available.png │ │ ├── ic_voice_focus.png │ │ ├── ic_voice_off.png │ │ ├── ic_voice_recording.png │ │ ├── key_selector.9.png │ │ ├── touch_selector.9.png │ │ ├── vs_reactive_dark.png │ │ └── vs_reactive_light.png │ │ ├── drawable-nodpi-v4 │ │ ├── ic_ime_accent_close.png │ │ ├── ic_ime_alphabet.png │ │ ├── ic_ime_clipboard.png │ │ ├── ic_ime_delete.png │ │ ├── ic_ime_left_arrow.png │ │ ├── ic_ime_right_arrow.png │ │ ├── ic_ime_shift_lock_on.png │ │ ├── ic_ime_shift_lock_on_dark.png │ │ ├── ic_ime_shift_lock_on_dark2.png │ │ ├── ic_ime_shift_lock_on_dark3.png │ │ ├── ic_ime_shift_lock_on_white.png │ │ ├── ic_ime_shift_off.png │ │ ├── ic_ime_shift_on.png │ │ ├── ic_ime_space.png │ │ ├── ic_ime_symbols.png │ │ ├── ic_ime_voice.png │ │ ├── ic_ime_world.png │ │ ├── ic_launcher.png │ │ └── key_selector_square.png │ │ ├── drawable-xhdpi-v4 │ │ ├── ic_voice_available.png │ │ ├── ic_voice_focus.png │ │ ├── ic_voice_off.png │ │ ├── ic_voice_recording.png │ │ ├── key_selector.9.png │ │ ├── touch_selector.9.png │ │ ├── vs_reactive_dark.png │ │ └── vs_reactive_light.png │ │ ├── drawable-xxhdpi-v4 │ │ ├── key_selector.9.png │ │ └── touch_selector.9.png │ │ ├── drawable │ │ ├── selector_caps_shift.xml │ │ ├── vs_micbtn_off_selector.xml │ │ ├── vs_micbtn_on_selector.xml │ │ └── vs_micbtn_rec_selector.xml │ │ ├── layout │ │ ├── activity_kb_layout.xml │ │ ├── candidate.xml │ │ ├── input_leanback.xml │ │ ├── lang_selection_dialog.xml │ │ ├── lang_selection_dialog_title.xml │ │ ├── recognizer_view.xml │ │ ├── root_leanback.xml │ │ └── selector.xml │ │ ├── mipmap-nodpi-v30 │ │ └── ic_launcher_main.png │ │ ├── mipmap-nodpi │ │ ├── adaptive_icon.png │ │ ├── ic_banner_main.png │ │ ├── ic_launcher_main.png │ │ └── ic_launcher_main_round.png │ │ ├── values-ar-rXB │ │ └── strings.xml │ │ ├── values-ar │ │ └── strings.xml │ │ ├── values-bg │ │ └── strings.xml │ │ ├── values-de │ │ ├── strings.xml │ │ └── themes.xml │ │ ├── values-el │ │ └── strings.xml │ │ ├── values-es │ │ ├── values-fa │ │ └── strings.xml │ │ ├── values-fr │ │ └── strings.xml │ │ ├── values-hdpi │ │ └── dimens.xml │ │ ├── values-is-rIS │ │ └── strings.xml │ │ ├── values-it │ │ └── strings.xml │ │ ├── values-mdpi │ │ └── dimens.xml │ │ ├── values-nl │ │ └── strings.xml │ │ ├── values-ro │ │ ├── strings.xml │ │ └── themes.xml │ │ ├── values-ru │ │ ├── strings.xml │ │ └── themes.xml │ │ ├── values-sl │ │ └── strings.xml │ │ ├── values-sv │ │ └── strings.xml │ │ ├── values-th │ │ └── strings.xml │ │ ├── values-tr │ │ └── strings.xml │ │ ├── values-tvdpi │ │ └── dimens.xml │ │ ├── values-uk │ │ ├── strings.xml │ │ └── themes.xml │ │ ├── values-xhdpi │ │ └── dimens.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── bitmap_sound_level_view.xml │ │ ├── colors.xml │ │ ├── colors_dark.xml │ │ ├── colors_dark2.xml │ │ ├── colors_dark3.xml │ │ ├── colors_white.xml │ │ ├── dimens.xml │ │ ├── fractions.xml │ │ ├── integers.xml │ │ ├── languages.xml │ │ ├── leanback_keyboard_view.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ ├── text_appearance.xml │ │ └── themes.xml │ │ └── xml │ │ ├── accent_a.xml │ │ ├── accent_ar_qm.xml │ │ ├── accent_ar_r.xml │ │ ├── accent_bg_i.xml │ │ ├── accent_c.xml │ │ ├── accent_d.xml │ │ ├── accent_de_b.xml │ │ ├── accent_e.xml │ │ ├── accent_fa_a.xml │ │ ├── accent_g.xml │ │ ├── accent_i.xml │ │ ├── accent_is_a.xml │ │ ├── accent_is_e.xml │ │ ├── accent_is_i.xml │ │ ├── accent_is_o.xml │ │ ├── accent_is_u.xml │ │ ├── accent_is_y.xml │ │ ├── accent_k.xml │ │ ├── accent_ka_q.xml │ │ ├── accent_ko_kr_e.xml │ │ ├── accent_ko_kr_o.xml │ │ ├── accent_ko_kr_p.xml │ │ ├── accent_ko_kr_q.xml │ │ ├── accent_ko_kr_r.xml │ │ ├── accent_ko_kr_t.xml │ │ ├── accent_ko_kr_w.xml │ │ ├── accent_l.xml │ │ ├── accent_n.xml │ │ ├── accent_o.xml │ │ ├── accent_s.xml │ │ ├── accent_slash.xml │ │ ├── accent_t.xml │ │ ├── accent_u.xml │ │ ├── accent_voice.xml │ │ ├── accent_y.xml │ │ ├── accent_z.xml │ │ ├── azerty_bg.xml │ │ ├── azerty_en_us.xml │ │ ├── azerty_fr.xml │ │ ├── azerty_tr.xml │ │ ├── empty_kbd.xml │ │ ├── method.xml │ │ ├── number.xml │ │ ├── popup_symbols.xml │ │ ├── qwerty_ar.xml │ │ ├── qwerty_bg.xml │ │ ├── qwerty_da.xml │ │ ├── qwerty_de.xml │ │ ├── qwerty_el.xml │ │ ├── qwerty_en_us.xml │ │ ├── qwerty_es_us.xml │ │ ├── qwerty_fa.xml │ │ ├── qwerty_fr.xml │ │ ├── qwerty_he.xml │ │ ├── qwerty_is.xml │ │ ├── qwerty_it.xml │ │ ├── qwerty_ka.xml │ │ ├── qwerty_ko_kr.xml │ │ ├── qwerty_nl.xml │ │ ├── qwerty_ro.xml │ │ ├── qwerty_ru.xml │ │ ├── qwerty_sl.xml │ │ ├── qwerty_sv.xml │ │ ├── qwerty_th.xml │ │ ├── qwerty_tr.xml │ │ ├── qwerty_uk.xml │ │ ├── shift_0.xml │ │ ├── shift_1.xml │ │ ├── shift_2.xml │ │ ├── shift_3.xml │ │ ├── shift_4.xml │ │ ├── shift_4_en_gb.xml │ │ ├── shift_4_en_in.xml │ │ ├── shift_4_eu.xml │ │ ├── shift_5.xml │ │ ├── shift_6.xml │ │ ├── shift_7.xml │ │ ├── shift_8.xml │ │ ├── shift_9.xml │ │ ├── shift_aa.xml │ │ ├── shift_ae.xml │ │ ├── shift_ao.xml │ │ ├── shift_b.xml │ │ ├── shift_cc.xml │ │ ├── shift_f.xml │ │ ├── shift_h.xml │ │ ├── shift_j.xml │ │ ├── shift_m.xml │ │ ├── shift_n_es.xml │ │ ├── shift_nn_es.xml │ │ ├── shift_oo.xml │ │ ├── shift_ox.xml │ │ ├── shift_p.xml │ │ ├── shift_q.xml │ │ ├── shift_r.xml │ │ ├── shift_uu.xml │ │ ├── shift_v.xml │ │ ├── shift_w.xml │ │ ├── shift_x.xml │ │ ├── shift_y.xml │ │ ├── sym_azerty.xml │ │ ├── sym_en_us.xml │ │ ├── sym_eu.xml │ │ └── sym_fr.xml │ ├── origin │ ├── java │ │ └── com │ │ │ └── liskovsoft │ │ │ └── leankeyboard │ │ │ ├── activity │ │ │ └── settings │ │ │ │ └── KbActivationActivity.java │ │ │ └── fragments │ │ │ └── settings │ │ │ └── AboutFragment.java │ └── res │ │ └── values │ │ └── strings.xml │ ├── playstore │ ├── java │ │ └── com │ │ │ └── liskovsoft │ │ │ └── leankeyboard │ │ │ ├── activity │ │ │ └── settings │ │ │ │ └── KbActivationActivity.java │ │ │ └── fragments │ │ │ └── settings │ │ │ └── AboutFragment.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── liskovsoft │ └── leankeykeyboard │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | /screen.png 2 | notes.txt 3 | /other 4 | /files 5 | /misc 6 | /releases 7 | tmp/ 8 | *_bak* 9 | *_tmp 10 | *.bak* 11 | /.idea 12 | *.apk 13 | *.7z 14 | *.iml 15 | .gradle 16 | /local.properties 17 | /.idea/workspace.xml 18 | /.idea/libraries 19 | .DS_Store 20 | /build 21 | /captures 22 | .externalNativeBuild 23 | fabric.properties 24 | *BAK.java 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Logo of LeanKeyboard](img/leankeykeyboard_logo_small.png "Logo of LeanKeyboard") LeanKeyboard 2 | ========= 3 | 4 | [![MPLv2 License](http://img.shields.io/badge/license-MPLv2-blue.svg?style=flat-square)](https://www.mozilla.org/MPL/2.0/) 5 | 6 | __LeanKeyboard: Keyboard for Android-based set-top boxes and TVs:__ 7 | 8 | * Google Play page 9 | * Telegram group 10 | 11 | ### Features: 12 | * Designed for TV screens. 13 | * Any remote controller support. 14 | * Supports dozens of languages. 15 | * Doesn't depend on Google Services. 16 | * __No root required!__ 17 | 18 | __Tip: Switch to other language with language button or by long press on the space bar__ 19 | 20 | __Tip: Do long press on the language button to choose between available languages__ 21 | 22 | ### Screenshots: 23 | * __[Open screenshots](#screens)__ 24 | 25 | ### Install LeanKeyboard: 26 | __Easy installation in less than 10 minutes with only FireTV__ 27 | * Install LeanKeyKeyboard (only FireTV needed) 28 | 29 | __Standard installation via ADB__ 30 | * If you don't know how to sideload/install apps via ADB, read a tutorial (e.g. this one) 31 | * Download latest LeanKeyKeyboard APK and sideload/install with adb: 32 | * *adb install -r LeanKeyboard.apk* 33 | * Enjoy :) 34 | 35 | ### Donation: 36 | If you want to support my developments you are welcome to buy me a cup of coffee :) 37 | 38 | 39 | * [**Patreon**](https://www.patreon.com/yuliskov) 40 | * **PayPal**: firsthash at gmail.com 41 | * **BTC**: 1JAT5VVWarVBkpVbNDn8UA8HXNdrukuBSx 42 | * **LTC**: ltc1qgc24eq9jl9cq78qnd5jpqhemkajg9vudwyd8pw 43 | * **ETH**: 0xe455E21a085ae195a097cd4F456051A9916A5064 44 | * **ETC**: 0x209eCd33Fa61fA92167595eB3Aea92EE1905c815 45 | * **XMR**: 48QsMjqfkeW54vkgKyRnjodtYxdmLk6HXfTWPSZoaFPEDpoHDwFUciGCe1QC9VAeGrgGw4PKNAksX9RW7myFqYJQDN5cHGT 46 | * **BNB**: bnb1amjr7fauftxxyhe4f95280vklctj243k9u55fq 47 | * **DOGE**: DBnqJwJs2GJBxrCDsi5bXwSmjnz8uGdUpB 48 | * **eUSDT**: 0xe455e21a085ae195a097cd4f456051a9916a5064 49 | 50 | ### Reviews / Articles: 51 | * [__XDA Discussion__](https://forum.xda-developers.com/fire-tv/general/guide-change-screen-keyboard-to-leankey-t3527675) 52 | 53 | ### Changelog: 54 | * [Check releases page for changelog ..](https://github.com/yuliskov/LeanKeyboard/releases) 55 | 56 | ### Contributors: 57 | * __[aglt](https://github.com/aglt)__ (Icelandic lang) 58 | * __[rabin111](https://github.com/rabin111)__ (Thai lang) 59 | 60 | ### Developer: 61 | * __[yuliskov](https://github.com/yuliskov)__ (design & coding) 62 | 63 | ### Screens: 64 | ![Screenshot of LeanKeyboard](img/leankeykeyboard_screenshot_01.png "Screenshot of LeanKeyboard") 65 | ![Screenshot of LeanKeyboard](img/leankeykeyboard_screenshot_02.png "Screenshot of LeanKeyboard") 66 | ![Screenshot of LeanKeyboard](img/leankeykeyboard_screenshot_03.png "Screenshot of LeanKeyboard") 67 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | mavenCentral() 7 | // jcenter() 8 | // maven { 9 | // url 'https://maven.google.com/' 10 | // name 'Google' 11 | // } 12 | // google() 13 | } 14 | dependencies { 15 | classpath 'com.android.tools.build:gradle:8.5.0' 16 | 17 | // NOTE: Do not place your application dependencies here; they belong 18 | // in the individual module build.gradle files 19 | } 20 | // WARNING: don't use 'project.ext' because IDE 'Cannot infer argument type' 21 | // https://stackoverflow.com/questions/20404476/how-to-define-common-android-properties-for-all-modules-using-gradle 22 | // Gradle constants example: https://github.com/google/ExoPlayer 23 | ext { 24 | // Google Play SDK version requirements: 25 | // https://support.google.com/googleplay/android-developer/answer/11926878 26 | compileSdkVersion = 35 27 | buildToolsVersion = "35.0.0" 28 | minSdkVersion = 14 29 | targetSdkVersion = 35 30 | espressoCoreVersion = 'com.android.support.test.espresso:espresso-core:2.2.2' 31 | junitVersion = 'junit:junit:4.12' 32 | robolectricVersion = 'org.robolectric:robolectric:3.5.1' 33 | crashlyticsVersion = 'com.crashlytics.sdk.android:crashlytics:2.8.0@aar' 34 | // androidx migration: 35 | // https://developer.android.com/jetpack/androidx/migrate 36 | // https://developer.android.com/jetpack/androidx/migrate/artifact-mappings 37 | appCompatXVersion = 'androidx.appcompat:appcompat:1.1.0' 38 | constraintXVersion = 'androidx.constraintlayout:constraintlayout:1.1.3' 39 | supportXVersion = 'androidx.legacy:legacy-support-v4:1.0.0' 40 | leanbackCompatXVersion = 'androidx.leanback:leanback:1.0.0' 41 | designXVersion = 'com.google.android.material:material:1.0.0' 42 | voiceOverlayVersion = 'com.algolia.instantsearch:voice:1.1.0' // https://github.com/algolia/voice-overlay-android 43 | } 44 | } 45 | 46 | allprojects { 47 | repositories { 48 | google() 49 | mavenCentral() 50 | //jcenter() 51 | // com.android.support libs 52 | //maven { url 'https://maven.google.com' } 53 | } 54 | 55 | gradle.projectsEvaluated { 56 | tasks.withType(JavaCompile) { 57 | options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" 58 | } 59 | } 60 | } 61 | 62 | task clean(type: Delete) { 63 | delete rootProject.buildDir 64 | } 65 | 66 | // Fix 'Namespace not specified' 67 | // https://stackoverflow.com/questions/76300671/android-getting-error-namespace-not-specified 68 | // subprojects { 69 | // afterEvaluate { project -> 70 | // if (project.hasProperty('android')) { 71 | // project.android { 72 | // if (namespace == null) { 73 | // namespace project.group 74 | // } 75 | // } 76 | // } 77 | // } 78 | // } 79 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | android.useAndroidX=true 2 | android.enableJetifier=true 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jan 16 19:59:54 EET 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /img/leankeykeyboard_logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/img/leankeykeyboard_logo_small.png -------------------------------------------------------------------------------- /img/leankeykeyboard_screenshot_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/img/leankeykeyboard_screenshot_01.png -------------------------------------------------------------------------------- /img/leankeykeyboard_screenshot_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/img/leankeykeyboard_screenshot_02.png -------------------------------------------------------------------------------- /img/leankeykeyboard_screenshot_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/img/leankeykeyboard_screenshot_03.png -------------------------------------------------------------------------------- /img/screen4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/img/screen4.png -------------------------------------------------------------------------------- /img/screen5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/img/screen5.png -------------------------------------------------------------------------------- /leankeykeyboard/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /playstore 3 | /origin 4 | -------------------------------------------------------------------------------- /leankeykeyboard/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | // Latest gradle fix: https://stackoverflow.com/questions/76300671/android-getting-error-namespace-not-specified 5 | namespace 'com.liskovsoft.leankeykeyboard' 6 | 7 | // Latest gradle fix: https://stackoverflow.com/questions/22604627/gradle-buildconfigfield-buildconfig-cannot-resolve-symbol 8 | buildFeatures { 9 | buildConfig = true 10 | } 11 | 12 | // FIX: Default interface methods are only supported starting with Android N (--min-api 24) 13 | compileOptions { 14 | sourceCompatibility JavaVersion.VERSION_1_8 15 | targetCompatibility JavaVersion.VERSION_1_8 16 | } 17 | 18 | compileSdkVersion project.properties.compileSdkVersion 19 | buildToolsVersion project.properties.buildToolsVersion 20 | 21 | defaultConfig { 22 | applicationId "org.liskovsoft.leankeykeyboard.pro" 23 | minSdkVersion project.properties.minSdkVersion 24 | targetSdkVersion project.properties.targetSdkVersion 25 | versionCode 202 26 | versionName "6.1.32" 27 | 28 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 29 | 30 | } 31 | buildTypes { 32 | release { 33 | // https://medium.com/@angelhiadefiesta/how-to-obfuscate-in-android-with-proguard-acab47701577 34 | minifyEnabled true // enable obfuscation 35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 36 | } 37 | } 38 | 39 | // naming example: SmartYouTubeTV_Xwalk_v6.8.12_r.apk 40 | // https://stackoverflow.com/questions/18332474/how-to-set-versionname-in-apk-filename-using-gradle 41 | applicationVariants.all { variant -> 42 | variant.outputs.each { output -> 43 | def project = "LeanKeyboard" 44 | // Latest gradle fix: https://stackoverflow.com/questions/62075122/no-such-property-variantconfiguration-for-class 45 | def buildType = variant.buildType.name.take(1) 46 | def version = variant.versionName 47 | def flavor = variant.productFlavors[-1].name 48 | 49 | def newApkName = sprintf("%s_v%s_%s_%s.apk", [project, version, flavor, buildType]) 50 | 51 | output.outputFileName = new File(newApkName) 52 | } 53 | } 54 | 55 | lintOptions { 56 | abortOnError true 57 | disable 'MissingTranslation' 58 | disable 'NewApi' 59 | } 60 | 61 | // gradle 4.6 migration: disable dimensions mechanism 62 | // more: https://proandroiddev.com/advanced-android-flavors-part-4-a-new-version-fc2ad80c01bb 63 | flavorDimensions "default" 64 | 65 | productFlavors { 66 | playstore { 67 | applicationId "org.liskovsoft.androidtv.rukeyboard" 68 | } 69 | origin { 70 | applicationId "com.liskovsoft.leankeyboard" 71 | } 72 | } 73 | } 74 | 75 | dependencies { 76 | implementation fileTree(dir: 'libs', include: ['*.jar']) 77 | androidTestImplementation(project.properties.espressoCoreVersion, { 78 | exclude group: 'com.android.support', module: 'support-annotations' 79 | }) 80 | testImplementation project.properties.junitVersion 81 | implementation project.properties.appCompatXVersion 82 | implementation project.properties.leanbackCompatXVersion 83 | implementation project.properties.constraintXVersion 84 | implementation project.properties.designXVersion 85 | implementation project.properties.voiceOverlayVersion 86 | } 87 | -------------------------------------------------------------------------------- /leankeykeyboard/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\portable\dev\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /leankeykeyboard/src/androidTest/java/com/liskovsoft/leankeykeyboard/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeykeyboard; 2 | 3 | import android.content.Context; 4 | import androidx.test.InstrumentationRegistry; 5 | import androidx.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.liskovsoft.leankeykeyboard", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/activity/PermissionsActivity.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import androidx.annotation.NonNull; 6 | import androidx.fragment.app.FragmentActivity; 7 | import com.liskovsoft.leankeyboard.helpers.PermissionHelpers; 8 | import com.liskovsoft.leankeyboard.receiver.RestartServiceReceiver; 9 | 10 | public class PermissionsActivity extends FragmentActivity { 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | 15 | checkPermissions(); 16 | } 17 | 18 | @Override 19 | protected void onStop() { 20 | super.onStop(); 21 | 22 | // restart kbd service 23 | Intent intent = new Intent(this, RestartServiceReceiver.class); 24 | sendBroadcast(intent); 25 | } 26 | 27 | @Override 28 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 29 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 30 | 31 | checkPermissions(); 32 | } 33 | 34 | private void checkPermissions() { 35 | if (!PermissionHelpers.hasMicPermissions(this)) { 36 | PermissionHelpers.verifyMicPermissions(this); 37 | } else if (!PermissionHelpers.hasStoragePermissions(this)) { 38 | PermissionHelpers.verifyStoragePermissions(this); 39 | } else { 40 | finish(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/activity/settings/KbLayoutActivity.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.activity.settings; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import androidx.fragment.app.FragmentActivity; 6 | import androidx.leanback.app.GuidedStepSupportFragment; 7 | import com.liskovsoft.leankeyboard.fragments.settings.KbLayoutFragment; 8 | import com.liskovsoft.leankeyboard.receiver.RestartServiceReceiver; 9 | 10 | public class KbLayoutActivity extends FragmentActivity { 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | 15 | GuidedStepSupportFragment.addAsRoot(this, new KbLayoutFragment(), android.R.id.content); 16 | } 17 | 18 | @Override 19 | protected void onStop() { 20 | super.onStop(); 21 | 22 | // restart kbd service 23 | Intent intent = new Intent(this, RestartServiceReceiver.class); 24 | sendBroadcast(intent); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/activity/settings/KbSettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.activity.settings; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import androidx.fragment.app.FragmentActivity; 6 | import androidx.leanback.app.GuidedStepSupportFragment; 7 | import com.liskovsoft.leankeyboard.fragments.settings.KbSettingsFragment; 8 | import com.liskovsoft.leankeyboard.receiver.RestartServiceReceiver; 9 | 10 | public class KbSettingsActivity extends FragmentActivity { 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | 15 | GuidedStepSupportFragment.addAsRoot(this, new KbSettingsFragment(), android.R.id.content); 16 | } 17 | 18 | @Override 19 | protected void onStop() { 20 | super.onStop(); 21 | 22 | // restart kbd service 23 | Intent intent = new Intent(this, RestartServiceReceiver.class); 24 | sendBroadcast(intent); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/activity/settings/KbSettingsActivity2.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.activity.settings; 2 | 3 | public class KbSettingsActivity2 extends KbSettingsActivity { 4 | } 5 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/KeyboardBuilder.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.keyboards; 2 | 3 | import android.inputmethodservice.Keyboard; 4 | import androidx.annotation.Nullable; 5 | 6 | public interface KeyboardBuilder { 7 | Keyboard createAbcKeyboard(); 8 | Keyboard createSymKeyboard(); 9 | Keyboard createNumKeyboard(); 10 | } 11 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/KeyboardFactory.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.keyboards; 2 | 3 | import android.content.Context; 4 | 5 | import java.util.List; 6 | 7 | public interface KeyboardFactory { 8 | List getAllAvailableKeyboards(Context context); 9 | boolean needUpdate(); 10 | } 11 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/KeyboardInfo.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.keyboards; 2 | 3 | public interface KeyboardInfo { 4 | String getLangCode(); 5 | void setLangCode(String langCode); 6 | String getLangName(); 7 | void setLangName(String langName); 8 | boolean isEnabled(); 9 | void setEnabled(boolean enabled); 10 | boolean isAzerty(); 11 | void setIsAzerty(boolean enabled); 12 | } 13 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/KeyboardManager.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.keyboards; 2 | 3 | import android.content.Context; 4 | import android.inputmethodservice.Keyboard; 5 | import com.liskovsoft.leankeyboard.addons.keyboards.intkeyboards.ResKeyboardFactory; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class KeyboardManager { 11 | private final Context mContext; 12 | private final KeyboardStateManager mStateManager; 13 | private List mKeyboardBuilders; 14 | private List mAllKeyboards; 15 | private final KeyboardFactory mKeyboardFactory; 16 | private int mKeyboardIndex = 0; 17 | 18 | public static class KeyboardData { 19 | public Keyboard abcKeyboard; 20 | public Keyboard symKeyboard; 21 | public Keyboard numKeyboard; 22 | } 23 | 24 | public KeyboardManager(Context ctx) { 25 | mContext = ctx; 26 | mStateManager = new KeyboardStateManager(mContext, this); 27 | mKeyboardFactory = new ResKeyboardFactory(mContext); 28 | mStateManager.restore(); 29 | } 30 | 31 | public void load() { 32 | mKeyboardBuilders = mKeyboardFactory.getAllAvailableKeyboards(mContext); 33 | mAllKeyboards = buildAllKeyboards(); 34 | } 35 | 36 | private List buildAllKeyboards() { 37 | List keyboards = new ArrayList<>(); 38 | if (!mKeyboardBuilders.isEmpty()) { 39 | for (KeyboardBuilder builder : mKeyboardBuilders) { 40 | KeyboardData data = new KeyboardData(); 41 | data.abcKeyboard = builder.createAbcKeyboard(); 42 | data.symKeyboard = builder.createSymKeyboard(); 43 | data.numKeyboard = builder.createNumKeyboard(); 44 | 45 | keyboards.add(data); 46 | } 47 | } 48 | return keyboards; 49 | } 50 | 51 | /** 52 | * Performs callback to event handlers 53 | */ 54 | private void onNextKeyboard() { 55 | mStateManager.onNextKeyboard(); 56 | } 57 | 58 | /** 59 | * Get next keyboard from internal source (looped) 60 | */ 61 | public KeyboardData next() { 62 | if (mKeyboardFactory.needUpdate() || mAllKeyboards == null) { 63 | load(); 64 | } 65 | 66 | ++mKeyboardIndex; 67 | 68 | mKeyboardIndex = mKeyboardIndex < mAllKeyboards.size() ? mKeyboardIndex : 0; 69 | 70 | KeyboardData kbd = mAllKeyboards.get(mKeyboardIndex); 71 | 72 | if (kbd == null) { 73 | throw new IllegalStateException(String.format("Keyboard %s not initialized", mKeyboardIndex)); 74 | } 75 | 76 | onNextKeyboard(); 77 | 78 | return kbd; 79 | } 80 | 81 | public int getIndex() { 82 | return mKeyboardIndex; 83 | } 84 | 85 | public void setIndex(int idx) { 86 | mKeyboardIndex = idx; 87 | } 88 | 89 | /** 90 | * Get current keyboard 91 | */ 92 | public KeyboardData get() { 93 | if (mAllKeyboards == null) { 94 | load(); 95 | } 96 | 97 | if (mAllKeyboards.size() <= mKeyboardIndex) { 98 | mKeyboardIndex = 0; 99 | } 100 | 101 | return mAllKeyboards.get(mKeyboardIndex); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/KeyboardStateManager.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.keyboards; 2 | 3 | import android.content.Context; 4 | import com.liskovsoft.leankeyboard.utils.LeanKeyPreferences; 5 | 6 | public class KeyboardStateManager { 7 | private final Context mContext; 8 | private final KeyboardManager mManager; 9 | private final LeanKeyPreferences mPrefs; 10 | 11 | public KeyboardStateManager(Context context, KeyboardManager manager) { 12 | mContext = context; 13 | mManager = manager; 14 | mPrefs = LeanKeyPreferences.instance(mContext); 15 | } 16 | 17 | public void restore() { 18 | int idx = mPrefs.getKeyboardIndex(); 19 | mManager.setIndex(idx); 20 | } 21 | 22 | public void onNextKeyboard() { 23 | mPrefs.setKeyboardIndex(mManager.getIndex()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/extkeyboards/addons/AddOn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Menny Even-Danan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.liskovsoft.leankeyboard.addons.keyboards.extkeyboards.addons; 18 | 19 | import android.content.Context; 20 | import androidx.annotation.NonNull; 21 | import androidx.annotation.Nullable; 22 | 23 | public interface AddOn { 24 | interface AddOnResourceMapping { 25 | /*@AttrRes 26 | int getLocalAttrIdFromRemote(@AttrRes int remoteAttributeResourceId);*/ 27 | 28 | int[] getRemoteStyleableArrayFromLocal(int[] localStyleableArray); 29 | } 30 | 31 | int INVALID_RES_ID = 0; 32 | 33 | String getId(); 34 | 35 | String getName(); 36 | 37 | String getDescription(); 38 | 39 | String getPackageName(); 40 | 41 | @Nullable 42 | Context getPackageContext(); 43 | 44 | int getSortIndex(); 45 | 46 | @NonNull 47 | AddOnResourceMapping getResourceMapping(); 48 | } 49 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/extkeyboards/addons/Support.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.keyboards.extkeyboards.addons; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.util.SparseIntArray; 6 | 7 | import androidx.annotation.NonNull; 8 | import com.liskovsoft.leankeyboard.addons.keyboards.extkeyboards.utils.log.Logger; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | class Support { 14 | private static final String TAG = Support.class.getName(); 15 | 16 | /** 17 | * Creates a mapping between the local styleable and the remote. 18 | * @param localStyleableArray the local styleable to map against 19 | * @param localContext local APK's Context 20 | * @param remoteContext remote package's Context 21 | * @param attributeIdMap a mapping between the remote-id -> local-id 22 | * @return Always returns the remote version of localStyleableArray 23 | */ 24 | public static int[] createBackwardCompatibleStyleable(@NonNull int[] localStyleableArray, @NonNull Context localContext, @NonNull Context remoteContext, @NonNull SparseIntArray attributeIdMap) { 25 | if (localContext == null) throw new NullPointerException("askContext can not be null"); 26 | if (remoteContext == null) throw new NullPointerException("context can not be null"); 27 | 28 | final String remotePackageName = remoteContext.getPackageName(); 29 | if (localContext.getPackageName().equals(remotePackageName)) { 30 | Logger.d(TAG, "This is a local context ("+remotePackageName+"), optimization will be done."); 31 | //optimization 32 | for(int attrId : localStyleableArray) { 33 | attributeIdMap.put(attrId, attrId); 34 | } 35 | return localStyleableArray; 36 | } 37 | final Resources localRes = localContext.getResources(); 38 | final Resources remoteRes = remoteContext.getResources(); 39 | List styleableIdList = new ArrayList<>(localStyleableArray.length); 40 | for(int attrId : localStyleableArray) { 41 | final boolean isAndroidAttribute = localRes.getResourcePackageName(attrId).equals("android"); 42 | final int remoteAttrId; 43 | 44 | if (isAndroidAttribute) { 45 | //android attribute IDs are the same always. So, I can optimize. 46 | remoteAttrId = attrId; 47 | } else { 48 | final String attributeName = localRes.getResourceEntryName(attrId); 49 | remoteAttrId = remoteRes.getIdentifier(attributeName, "attr", remotePackageName); 50 | Logger.d(TAG, "attr "+attributeName+", local id "+attrId+", remote id "+remoteAttrId); 51 | } 52 | if (remoteAttrId != 0) { 53 | attributeIdMap.put(remoteAttrId, attrId); 54 | styleableIdList.add(remoteAttrId); 55 | } 56 | } 57 | final int[] remoteMappedStyleable = new int[styleableIdList.size()]; 58 | for(int i=0; i= Build.VERSION_CODES.FROYO) { 43 | Log.wtf(TAG, text); 44 | } else { 45 | Log.e(TAG+" WTF", text); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/extkeyboards/utils/log/LogProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Menny Even-Danan 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.liskovsoft.leankeyboard.addons.keyboards.extkeyboards.utils.log; 18 | 19 | public interface LogProvider { 20 | 21 | void v(String TAG, String text); 22 | 23 | void d(String TAG, String text); 24 | 25 | void yell(String TAG, String text); 26 | 27 | void i(String TAG, String text); 28 | 29 | void w(String TAG, String text); 30 | 31 | void e(String TAG, String text); 32 | 33 | void wtf(String TAG, String text); 34 | } 35 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/extkeyboards/utils/log/NullLogProvider.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.keyboards.extkeyboards.utils.log; 2 | 3 | /** 4 | * Doesn't do anything. For release. 5 | */ 6 | public class NullLogProvider implements LogProvider { 7 | @Override 8 | public void v(String TAG, String text) { 9 | } 10 | 11 | @Override 12 | public void d(String TAG, String text) { 13 | } 14 | 15 | @Override 16 | public void yell(String TAG, String text) { 17 | 18 | } 19 | 20 | @Override 21 | public void i(String TAG, String text) { 22 | 23 | } 24 | 25 | @Override 26 | public void w(String TAG, String text) { 27 | 28 | } 29 | 30 | @Override 31 | public void e(String TAG, String text) { 32 | 33 | } 34 | 35 | @Override 36 | public void wtf(String TAG, String text) { 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/intkeyboards/CheckedSource.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.keyboards.intkeyboards; 2 | 3 | import java.util.List; 4 | 5 | public interface CheckedSource { 6 | List getItems(); 7 | 8 | interface CheckedItem { 9 | long getId(); 10 | String getTitle(); 11 | void onClick(boolean checked); 12 | boolean getChecked(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/intkeyboards/KeyboardInfoAdapter.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.keyboards.intkeyboards; 2 | 3 | import android.content.Context; 4 | import com.liskovsoft.leankeyboard.addons.keyboards.KeyboardInfo; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class KeyboardInfoAdapter implements CheckedSource { 10 | private final Context mContext; 11 | private final List mInfos; 12 | 13 | public KeyboardInfoAdapter(Context context) { 14 | mContext = context; 15 | mInfos = ResKeyboardInfo.getAllKeyboardInfos(context); 16 | } 17 | 18 | @Override 19 | public List getItems() { 20 | List result = new ArrayList<>(); 21 | 22 | int counter = 99; 23 | 24 | for (KeyboardInfo info : mInfos) { 25 | int finalCounter = counter++; 26 | 27 | CheckedItem item = new CheckedItem() { 28 | private final KeyboardInfo mInfo = info; 29 | private final int mCounter = finalCounter; 30 | 31 | @Override 32 | public long getId() { 33 | return mCounter; 34 | } 35 | 36 | @Override 37 | public String getTitle() { 38 | return mInfo.getLangName(); 39 | } 40 | 41 | @Override 42 | public void onClick(boolean checked) { 43 | if (mInfo.isEnabled() == checked) { 44 | return; 45 | } 46 | 47 | mInfo.setEnabled(checked); 48 | ResKeyboardInfo.updateAllKeyboardInfos(mContext, mInfos); 49 | } 50 | 51 | @Override 52 | public boolean getChecked() { 53 | return mInfo.isEnabled(); 54 | } 55 | }; 56 | 57 | result.add(item); 58 | } 59 | 60 | return result; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/keyboards/intkeyboards/ResKeyboardInfo.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.keyboards.intkeyboards; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.preference.PreferenceManager; 6 | import androidx.annotation.NonNull; 7 | import com.liskovsoft.leankeyboard.addons.keyboards.KeyboardInfo; 8 | import com.liskovsoft.leankeykeyboard.R; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class ResKeyboardInfo implements KeyboardInfo { 14 | private static boolean sNeedUpdate; 15 | private boolean mEnabled; 16 | private String mLangCode; 17 | private String mLangName; 18 | private boolean mIsAzerty; 19 | 20 | public static List getAllKeyboardInfos(Context ctx) { 21 | List result = new ArrayList<>(); 22 | String[] langs = ctx.getResources().getStringArray(R.array.additional_languages); 23 | for (final String langPair : langs) { 24 | String[] pairs = langPair.split("\\|"); 25 | final String langName = pairs[0]; 26 | final String langCode = pairs[1]; 27 | final boolean isAzerty = pairs.length >= 3 && "azerty".equals(pairs[2]); 28 | KeyboardInfo info = new ResKeyboardInfo(); 29 | info.setLangName(langName); 30 | info.setLangCode(langCode); 31 | info.setIsAzerty(isAzerty); 32 | // sync with prefs 33 | syncWithPrefs(ctx, info); 34 | result.add(info); 35 | } 36 | sNeedUpdate = false; 37 | return result; 38 | } 39 | 40 | public static void updateAllKeyboardInfos(Context ctx, List infos) { 41 | for (KeyboardInfo info : infos) { 42 | // update prefs 43 | updatePrefs(ctx, info); 44 | } 45 | sNeedUpdate = true; 46 | } 47 | 48 | private static void syncWithPrefs(Context ctx, KeyboardInfo info) { 49 | final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(ctx); 50 | final boolean kbdEnabled = sharedPreferences.getBoolean(info.toString(), false); 51 | info.setEnabled(kbdEnabled); 52 | } 53 | 54 | private static void updatePrefs(Context ctx, KeyboardInfo info) { 55 | final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(ctx); 56 | 57 | final SharedPreferences.Editor editor = sharedPreferences.edit(); 58 | editor.putBoolean(info.toString(), info.isEnabled()); 59 | editor.apply(); 60 | } 61 | 62 | public static boolean needUpdate() { 63 | return sNeedUpdate; 64 | } 65 | 66 | @Override 67 | public boolean isEnabled() { 68 | return mEnabled; 69 | } 70 | 71 | @Override 72 | public String getLangCode() { 73 | return mLangCode; 74 | } 75 | 76 | @Override 77 | public String getLangName() { 78 | return mLangName; 79 | } 80 | 81 | @Override 82 | public void setLangName(String langName) { 83 | mLangName = langName; 84 | } 85 | 86 | @Override 87 | public void setLangCode(String langCode) { 88 | mLangCode = langCode; 89 | } 90 | 91 | @Override 92 | public void setEnabled(boolean enabled) { 93 | mEnabled = enabled; 94 | } 95 | 96 | @Override 97 | public boolean isAzerty() { 98 | return mIsAzerty; 99 | } 100 | 101 | @Override 102 | public void setIsAzerty(boolean isAzerty) { 103 | mIsAzerty = isAzerty; 104 | } 105 | 106 | @NonNull 107 | @Override 108 | public String toString() { 109 | return String.format("{Name: %s, Code: %s, IsAzerty: %b}", mLangName, mLangCode, mIsAzerty); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/resize/KeyboardWrapper.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.resize; 2 | 3 | import android.content.Context; 4 | import android.inputmethodservice.Keyboard; 5 | import androidx.annotation.Nullable; 6 | import com.liskovsoft.leankeyboard.ime.LeanbackKeyboardContainer; 7 | import com.liskovsoft.leankeykeyboard.R; 8 | 9 | import java.util.List; 10 | 11 | public class KeyboardWrapper extends Keyboard { 12 | private Keyboard mKeyboard; 13 | private int mHeight = -1; 14 | private float mHeightFactor = 1.0f; 15 | private float mWidthFactor = 1.0f; 16 | 17 | public KeyboardWrapper(Context context, int xmlLayoutResId) { 18 | super(context, xmlLayoutResId); 19 | } 20 | 21 | public KeyboardWrapper(Context context, int xmlLayoutResId, int modeId, int width, int height) { 22 | super(context, xmlLayoutResId, modeId, width, height); 23 | } 24 | 25 | public KeyboardWrapper(Context context, int xmlLayoutResId, int modeId) { 26 | super(context, xmlLayoutResId, modeId); 27 | } 28 | 29 | public KeyboardWrapper(Context context, int layoutTemplateResId, CharSequence characters, int columns, int horizontalPadding) { 30 | super(context, layoutTemplateResId, characters, columns, horizontalPadding); 31 | } 32 | 33 | public static KeyboardWrapper from(Keyboard keyboard, Context context) { 34 | KeyboardWrapper wrapper = new KeyboardWrapper(context, R.xml.empty_kbd); 35 | wrapper.mKeyboard = keyboard; 36 | 37 | return wrapper; 38 | } 39 | 40 | @Override 41 | public List getKeys() { 42 | return mKeyboard.getKeys(); 43 | } 44 | 45 | @Override 46 | public List getModifierKeys() { 47 | return mKeyboard.getModifierKeys(); 48 | } 49 | 50 | @Override 51 | public int getHeight() { 52 | return (int)(mKeyboard.getHeight() * mHeightFactor); 53 | } 54 | 55 | @Override 56 | public int getMinWidth() { 57 | return (int)(mKeyboard.getMinWidth() * mWidthFactor); 58 | } 59 | 60 | @Override 61 | public boolean setShifted(boolean shiftState) { 62 | return mKeyboard.setShifted(shiftState); 63 | } 64 | 65 | @Override 66 | public boolean isShifted() { 67 | return mKeyboard.isShifted(); 68 | } 69 | 70 | @Override 71 | public int getShiftKeyIndex() { 72 | return mKeyboard.getShiftKeyIndex(); 73 | } 74 | 75 | @Override 76 | public int[] getNearestKeys(int x, int y) { 77 | return mKeyboard.getNearestKeys(x, y); 78 | } 79 | 80 | public void setHeightFactor(float factor) { 81 | mHeightFactor = factor; 82 | } 83 | 84 | public void setWidthFactor(float factor) { 85 | mWidthFactor = factor; 86 | } 87 | 88 | /** 89 | * Wrapper fix: {@link LeanbackKeyboardContainer#onModeChangeClick} 90 | */ 91 | @Override 92 | public boolean equals(@Nullable Object obj) { 93 | if (obj instanceof Keyboard) { 94 | return mKeyboard.equals(obj); 95 | } 96 | 97 | return false; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/resize/ResizeableLeanbackKeyboardView.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.resize; 2 | 3 | import android.content.Context; 4 | import android.inputmethodservice.Keyboard; 5 | import android.inputmethodservice.Keyboard.Key; 6 | import android.util.AttributeSet; 7 | import com.liskovsoft.leankeyboard.ime.LeanbackKeyboardView; 8 | import com.liskovsoft.leankeyboard.utils.LeanKeyPreferences; 9 | 10 | import java.util.List; 11 | 12 | public class ResizeableLeanbackKeyboardView extends LeanbackKeyboardView { 13 | private final LeanKeyPreferences mPrefs; 14 | private final int mKeyTextSizeOrigin; 15 | private final int mModeChangeTextSizeOrigin; 16 | private final float mSizeFactor = 1.3f; 17 | private int mKeyOriginWidth; 18 | 19 | public ResizeableLeanbackKeyboardView(Context context, AttributeSet attrs) { 20 | super(context, attrs); 21 | mPrefs = LeanKeyPreferences.instance(getContext()); 22 | mKeyTextSizeOrigin = mKeyTextSize; 23 | mModeChangeTextSizeOrigin = mModeChangeTextSize; 24 | } 25 | 26 | @Override 27 | public void setKeyboard(Keyboard keyboard) { 28 | if (mPrefs.getEnlargeKeyboard()) { 29 | mKeyTextSize = (int) (mKeyTextSizeOrigin * mSizeFactor); 30 | mModeChangeTextSize = (int) (mModeChangeTextSizeOrigin * mSizeFactor); 31 | 32 | keyboard = updateKeyboard(keyboard); 33 | } else { 34 | mKeyTextSize = mKeyTextSizeOrigin; 35 | mModeChangeTextSize = mModeChangeTextSizeOrigin; 36 | } 37 | 38 | mPaint.setTextSize(mKeyTextSize); 39 | 40 | super.setKeyboard(keyboard); 41 | } 42 | 43 | private Keyboard updateKeyboard(Keyboard keyboard) { 44 | List keys = keyboard.getKeys(); 45 | 46 | if (isNotSizedYet(keys.get(0))) { 47 | for (Key key : keys) { 48 | key.width *= mSizeFactor; 49 | key.height *= mSizeFactor; 50 | key.gap *= mSizeFactor; 51 | key.x *= mSizeFactor; 52 | key.y *= mSizeFactor; 53 | } 54 | } 55 | 56 | KeyboardWrapper wrapper = KeyboardWrapper.from(keyboard, getContext()); 57 | wrapper.setHeightFactor(mSizeFactor); 58 | wrapper.setWidthFactor(mSizeFactor); 59 | 60 | return wrapper; 61 | } 62 | 63 | private boolean isNotSizedYet(Key key) { 64 | boolean result = false; 65 | 66 | if (mKeyOriginWidth == 0) { 67 | mKeyOriginWidth = key.width; 68 | } 69 | 70 | if (mKeyOriginWidth == key.width) { 71 | result = true; 72 | } 73 | 74 | return result; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/voice/ActivityListener.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.voice; 2 | 3 | import android.content.Intent; 4 | 5 | interface ActivityListener { 6 | void onActivityResult(int requestCode, int resultCode, Intent data); 7 | } 8 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/voice/RecognizerCallback.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.voice; 2 | 3 | public interface RecognizerCallback { 4 | void openSearchPage(String searchText); 5 | } 6 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/voice/RecognizerIntentActivity.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.voice; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import androidx.annotation.Nullable; 6 | import androidx.appcompat.app.AppCompatActivity; 7 | 8 | public class RecognizerIntentActivity extends AppCompatActivity { 9 | public static RecognizerCallback sCallback; 10 | private VoiceSearchBridge mBridge; 11 | 12 | @Override 13 | protected void onCreate(@Nullable Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | 16 | mBridge = new VoiceSearchBridge(this, searchText -> sCallback.openSearchPage(searchText)); 17 | 18 | mBridge.displaySpeechRecognizers(); 19 | } 20 | 21 | @Override 22 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 23 | super.onActivityResult(requestCode, resultCode, data); 24 | 25 | mBridge.onActivityResult(requestCode, resultCode, data); 26 | 27 | finish(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/voice/RecognizerIntentWrapper.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.voice; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | 6 | public class RecognizerIntentWrapper { 7 | private final Context mContext; 8 | private RecognizerCallback mCallback; 9 | 10 | public RecognizerIntentWrapper(Context context) { 11 | mContext = context; 12 | } 13 | 14 | public void setListener(RecognizerCallback callback) { 15 | mCallback = callback; 16 | } 17 | 18 | public void startListening() { 19 | if (mCallback != null) { 20 | RecognizerIntentActivity.sCallback = mCallback; 21 | Intent intent = new Intent(mContext, RecognizerIntentActivity.class); 22 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 23 | mContext.startActivity(intent); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/voice/SearchCallback.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.voice; 2 | 3 | interface SearchCallback { 4 | void openSearchPage(String searchText); 5 | } 6 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/voice/SystemVoiceDialog.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.voice; 2 | 3 | import android.app.Activity; 4 | import android.content.ActivityNotFoundException; 5 | import android.content.Intent; 6 | import android.speech.RecognizerIntent; 7 | 8 | import java.util.List; 9 | 10 | class SystemVoiceDialog implements VoiceDialog, ActivityListener { 11 | private static final int SPEECH_REQUEST_CODE = 11; 12 | private final Activity mActivity; 13 | private final SearchCallback mCallback; 14 | 15 | public SystemVoiceDialog(Activity activity, SearchCallback callback) { 16 | mActivity = activity; 17 | mCallback = callback; 18 | } 19 | 20 | public boolean displaySpeechRecognizer() { 21 | Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 22 | intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, 23 | RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); 24 | try { 25 | mActivity.startActivityForResult(intent, SPEECH_REQUEST_CODE); 26 | } catch (ActivityNotFoundException e) { 27 | e.printStackTrace(); 28 | return false; 29 | } 30 | 31 | return true; 32 | } 33 | 34 | @Override 35 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 36 | // got speech-to-text result, switch to the search page 37 | if (requestCode == SPEECH_REQUEST_CODE && resultCode == -1) { 38 | List results = data.getStringArrayListExtra( 39 | RecognizerIntent.EXTRA_RESULTS); 40 | if (results != null && results.size() > 0) { 41 | mCallback.openSearchPage(results.get(0)); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/voice/VoiceDialog.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.voice; 2 | 3 | interface VoiceDialog { 4 | boolean displaySpeechRecognizer(); 5 | } 6 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/voice/VoiceOverlayDialog.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.voice; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | import com.algolia.instantsearch.voice.VoiceSpeechRecognizer; 5 | import com.algolia.instantsearch.voice.ui.Voice; 6 | import com.algolia.instantsearch.voice.ui.VoiceInputDialogFragment; 7 | import com.algolia.instantsearch.voice.ui.VoicePermissionDialogFragment; 8 | 9 | class VoiceOverlayDialog implements VoiceDialog, VoiceSpeechRecognizer.ResultsListener { 10 | private final AppCompatActivity mActivity; 11 | private final SearchCallback mCallback; 12 | 13 | private enum Tag { 14 | Permission, 15 | Voice 16 | } 17 | 18 | public VoiceOverlayDialog(AppCompatActivity activity, SearchCallback callback) { 19 | mActivity = activity; 20 | mCallback = callback; 21 | } 22 | 23 | @Override 24 | public boolean displaySpeechRecognizer() { 25 | if (!Voice.isRecordAudioPermissionGranted(mActivity)) { 26 | new VoicePermissionDialogFragment() 27 | .show(mActivity.getSupportFragmentManager(), Tag.Permission.name()); 28 | } else { 29 | showVoiceDialog(); 30 | } 31 | 32 | return true; 33 | } 34 | 35 | private void showVoiceDialog() { 36 | VoicePermissionDialogFragment dialog = getPermissionDialog(); 37 | 38 | if (dialog != null) { 39 | dialog.dismiss(); 40 | } 41 | 42 | VoiceInputDialogFragment voiceDialog = getVoiceDialog(); 43 | 44 | if (voiceDialog == null) { 45 | voiceDialog = new VoiceInputDialogFragment(); 46 | } else { 47 | voiceDialog.dismiss(); 48 | } 49 | 50 | voiceDialog.show(mActivity.getSupportFragmentManager(), Tag.Voice.name()); 51 | } 52 | 53 | private VoicePermissionDialogFragment getPermissionDialog() { 54 | return (VoicePermissionDialogFragment) mActivity.getSupportFragmentManager().findFragmentByTag(Tag.Permission.name()); 55 | } 56 | 57 | private VoiceInputDialogFragment getVoiceDialog() { 58 | return (VoiceInputDialogFragment) mActivity.getSupportFragmentManager().findFragmentByTag(Tag.Voice.name()); 59 | } 60 | 61 | @Override 62 | public void onResults(String[] strings) { 63 | if (strings.length > 0) { 64 | mCallback.openSearchPage(strings[0]); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/addons/voice/VoiceSearchBridge.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.addons.voice; 2 | 3 | import android.content.Intent; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | 6 | import java.util.ArrayList; 7 | 8 | class VoiceSearchBridge implements SearchCallback { 9 | private final ArrayList mDialogs; 10 | private final AppCompatActivity mActivity; 11 | private final RecognizerCallback mCallback; 12 | 13 | public VoiceSearchBridge(AppCompatActivity activity, RecognizerCallback callback) { 14 | mActivity = activity; 15 | mCallback = callback; 16 | mDialogs = new ArrayList<>(); 17 | mDialogs.add(new SystemVoiceDialog(activity, this)); 18 | mDialogs.add(new VoiceOverlayDialog(activity, this)); 19 | } 20 | 21 | public void displaySpeechRecognizers() { 22 | for (VoiceDialog dialog : mDialogs) { 23 | if (dialog.displaySpeechRecognizer()) { // fist successful attempt is used 24 | break; 25 | } 26 | } 27 | } 28 | 29 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 30 | for (VoiceDialog dialog : mDialogs) { 31 | if (dialog instanceof ActivityListener) { 32 | ((ActivityListener) dialog).onActivityResult(requestCode, resultCode, data); 33 | } 34 | } 35 | } 36 | 37 | @Override 38 | public void openSearchPage(String searchText) { 39 | if (mCallback != null) { 40 | mCallback.openSearchPage(searchText); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/fragments/settings/KbLayoutFragment.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.fragments.settings; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.os.Bundle; 6 | import androidx.annotation.NonNull; 7 | import androidx.core.content.ContextCompat; 8 | import androidx.leanback.widget.GuidanceStylist.Guidance; 9 | import com.liskovsoft.leankeyboard.addons.keyboards.intkeyboards.KeyboardInfoAdapter; 10 | import com.liskovsoft.leankeyboard.addons.keyboards.intkeyboards.CheckedSource; 11 | import com.liskovsoft.leankeyboard.addons.keyboards.intkeyboards.CheckedSource.CheckedItem; 12 | import com.liskovsoft.leankeykeyboard.R; 13 | 14 | public class KbLayoutFragment extends BaseSettingsFragment { 15 | @Override 16 | public void onAttach(Context context) { 17 | super.onAttach(context); 18 | 19 | initCheckedItems(); 20 | } 21 | 22 | @NonNull 23 | @Override 24 | public Guidance onCreateGuidance(Bundle savedInstanceState) { 25 | String title = getActivity().getResources().getString(R.string.kb_layout); 26 | String desc = getActivity().getResources().getString(R.string.kb_layout_desc); 27 | Drawable icon = ContextCompat.getDrawable(getActivity(), R.drawable.ic_launcher); 28 | 29 | return new Guidance( 30 | title, 31 | desc, 32 | "", 33 | icon 34 | ); 35 | } 36 | 37 | private void initCheckedItems() { 38 | CheckedSource source = new KeyboardInfoAdapter(getActivity()); 39 | for (CheckedItem item : source.getItems()) { 40 | addCheckedAction(item.getTitle(), item::getChecked, item::onClick); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/fragments/settings/KbSettingsFragment.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.fragments.settings; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.drawable.Drawable; 6 | import android.os.Bundle; 7 | import androidx.annotation.NonNull; 8 | import androidx.core.content.ContextCompat; 9 | import androidx.leanback.app.GuidedStepSupportFragment; 10 | import androidx.leanback.widget.GuidanceStylist.Guidance; 11 | import com.liskovsoft.leankeyboard.activity.settings.KbActivationActivity; 12 | import com.liskovsoft.leankeykeyboard.R; 13 | 14 | public class KbSettingsFragment extends BaseSettingsFragment { 15 | @Override 16 | public void onAttach(Context context) { 17 | super.onAttach(context); 18 | 19 | addNextAction(R.string.activate_keyboard, () -> { 20 | Intent intent = new Intent(getActivity(), KbActivationActivity.class); 21 | startActivity(intent); 22 | }); 23 | 24 | addNextAction(R.string.change_layout, () -> startGuidedFragment(new KbLayoutFragment())); 25 | 26 | addNextAction(R.string.change_theme, () -> startGuidedFragment(new KbThemeFragment())); 27 | 28 | addNextAction(R.string.misc, () -> startGuidedFragment(new MiscFragment())); 29 | 30 | addNextAction(R.string.about_desc, () -> startGuidedFragment(new AboutFragment())); 31 | } 32 | 33 | @NonNull 34 | @Override 35 | public Guidance onCreateGuidance(Bundle savedInstanceState) { 36 | String title = getActivity().getResources().getString(R.string.ime_name); 37 | String desc = getActivity().getResources().getString(R.string.kb_settings_desc); 38 | Drawable icon = ContextCompat.getDrawable(getActivity(), R.drawable.ic_launcher); 39 | 40 | return new Guidance( 41 | title, 42 | desc, 43 | "", 44 | icon 45 | ); 46 | } 47 | 48 | private void startGuidedFragment(GuidedStepSupportFragment fragment) { 49 | if (getFragmentManager() != null) { 50 | GuidedStepSupportFragment.add(getFragmentManager(), fragment); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/fragments/settings/KbThemeFragment.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.fragments.settings; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.os.Bundle; 6 | import androidx.annotation.NonNull; 7 | import androidx.core.content.ContextCompat; 8 | import androidx.leanback.widget.GuidanceStylist.Guidance; 9 | import com.liskovsoft.leankeyboard.utils.LeanKeyPreferences; 10 | import com.liskovsoft.leankeykeyboard.R; 11 | 12 | public class KbThemeFragment extends BaseSettingsFragment { 13 | private Context mContext; 14 | 15 | @Override 16 | public void onAttach(Context context) { 17 | super.onAttach(context); 18 | mContext = context; 19 | 20 | initRadioItems(); 21 | } 22 | 23 | @NonNull 24 | @Override 25 | public Guidance onCreateGuidance(Bundle savedInstanceState) { 26 | String title = getActivity().getResources().getString(R.string.kb_theme); 27 | String desc = getActivity().getResources().getString(R.string.kb_theme_desc); 28 | Drawable icon = ContextCompat.getDrawable(getActivity(), R.drawable.ic_launcher); 29 | 30 | return new Guidance( 31 | title, 32 | desc, 33 | "", 34 | icon 35 | ); 36 | } 37 | 38 | private void initRadioItems() { 39 | String[] themes = mContext.getResources().getStringArray(R.array.keyboard_themes); 40 | 41 | LeanKeyPreferences prefs = LeanKeyPreferences.instance(mContext); 42 | String currentTheme = prefs.getCurrentTheme(); 43 | 44 | for (String theme : themes) { 45 | String[] split = theme.split("\\|"); 46 | String themeName = split[0]; 47 | String themeId = split[1]; 48 | addRadioAction(themeName, () -> currentTheme.equals(themeId), (checked) -> prefs.setCurrentTheme(themeId)); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/fragments/settings/MiscFragment.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.fragments.settings; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.os.Bundle; 6 | import androidx.annotation.NonNull; 7 | import androidx.core.content.ContextCompat; 8 | import androidx.leanback.widget.GuidanceStylist.Guidance; 9 | import com.liskovsoft.leankeyboard.activity.settings.KbSettingsActivity2; 10 | import com.liskovsoft.leankeyboard.helpers.Helpers; 11 | import com.liskovsoft.leankeyboard.utils.LeanKeyPreferences; 12 | import com.liskovsoft.leankeykeyboard.R; 13 | 14 | public class MiscFragment extends BaseSettingsFragment { 15 | private LeanKeyPreferences mPrefs; 16 | private Context mContext; 17 | 18 | @Override 19 | public void onAttach(Context context) { 20 | super.onAttach(context); 21 | 22 | mContext = context; 23 | mPrefs = LeanKeyPreferences.instance(getActivity()); 24 | addCheckedAction(R.string.keep_on_screen, R.string.keep_on_screen_desc, mPrefs::getForceShowKeyboard, mPrefs::setForceShowKeyboard); 25 | addCheckedAction(R.string.increase_kbd_size, R.string.increase_kbd_size_desc, mPrefs::getEnlargeKeyboard, mPrefs::setEnlargeKeyboard); 26 | addCheckedAction(R.string.enable_suggestions, R.string.enable_suggestions_desc, mPrefs::getSuggestionsEnabled, mPrefs::setSuggestionsEnabled); 27 | addCheckedAction(R.string.show_launcher_icon, R.string.show_launcher_icon_desc, this::getLauncherIconShown, this::setLauncherIconShown); 28 | addCheckedAction(R.string.enable_cyclic_navigation, R.string.enable_cyclic_navigation_desc, mPrefs::isCyclicNavigationEnabled, mPrefs::setCyclicNavigationEnabled); 29 | } 30 | 31 | @NonNull 32 | @Override 33 | public Guidance onCreateGuidance(Bundle savedInstanceState) { 34 | String title = getActivity().getResources().getString(R.string.misc); 35 | String desc = getActivity().getResources().getString(R.string.misc_desc); 36 | Drawable icon = ContextCompat.getDrawable(getActivity(), R.drawable.ic_launcher); 37 | 38 | return new Guidance( 39 | title, 40 | desc, 41 | "", 42 | icon 43 | ); 44 | } 45 | 46 | private void setLauncherIconShown(boolean shown) { 47 | Helpers.setLauncherIconShown(mContext, KbSettingsActivity2.class, shown); 48 | } 49 | 50 | private boolean getLauncherIconShown() { 51 | return Helpers.getLauncherIconShown(mContext, KbSettingsActivity2.class); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/helpers/MessageHelpers.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.helpers; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.widget.Toast; 7 | 8 | public class MessageHelpers { 9 | private static long sExitMsgTimeMS = 0; 10 | private static final int LONG_MSG_TIMEOUT = 5000; 11 | 12 | public static void showMessage(final Context ctx, final String TAG, final Throwable ex) { 13 | showMessage(ctx, TAG, Helpers.toString(ex)); 14 | } 15 | 16 | public static void showMessage(final Context ctx, final String TAG, final String msg) { 17 | showMessage(ctx, String.format("%s: %s", TAG, msg)); 18 | } 19 | 20 | public static void showMessageThrottled(final Context ctx, final String msg) { 21 | // throttle msg calls 22 | if (System.currentTimeMillis() - sExitMsgTimeMS < LONG_MSG_TIMEOUT) { 23 | return; 24 | } 25 | sExitMsgTimeMS = System.currentTimeMillis(); 26 | showMessage(ctx, msg); 27 | } 28 | 29 | public static void showMessage(final Context ctx, final String msg) { 30 | if (ctx == null) { 31 | return; 32 | } 33 | 34 | Runnable toast = () -> { 35 | try { 36 | Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show(); 37 | } catch (Exception ex) { // NPE fix 38 | ex.printStackTrace(); 39 | } 40 | }; 41 | 42 | if (Looper.myLooper() == Looper.getMainLooper()) { 43 | toast.run(); 44 | } else { 45 | new Handler(Looper.getMainLooper()).post(toast); 46 | } 47 | } 48 | 49 | /** 50 | * Shows long toast message.
51 | * Uses resource id as message. 52 | * @param ctx context 53 | * @param resId resource id 54 | */ 55 | public static void showLongMessage(Context ctx, int resId) { 56 | showLongMessage(ctx, ctx.getResources().getString(resId)); 57 | } 58 | 59 | public static void showLongMessage(Context ctx, String msg) { 60 | for (int i = 0; i < 3; i++) { 61 | showMessage(ctx, msg); 62 | } 63 | } 64 | 65 | public static void showLongMessage(Context ctx, String TAG, String msg) { 66 | for (int i = 0; i < 3; i++) { 67 | showMessage(ctx, TAG, msg); 68 | } 69 | } 70 | 71 | /** 72 | * Shows toast message.
73 | * Uses resource id as message. 74 | * @param ctx context 75 | * @param resId resource id 76 | */ 77 | public static void showMessage(Context ctx, int resId) { 78 | showMessage(ctx, ctx.getResources().getString(resId)); 79 | } 80 | 81 | public static void showLongMessageEndPause(Context context, int resId) { 82 | showLongMessage(context, resId); 83 | 84 | try { 85 | Thread.sleep(5_000); 86 | } catch (InterruptedException e) { 87 | e.printStackTrace(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/helpers/PermissionHelpers.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.helpers; 2 | 3 | import android.Manifest; 4 | import android.annotation.TargetApi; 5 | import android.app.Activity; 6 | import android.content.Context; 7 | import android.content.pm.PackageManager; 8 | import android.os.Build.VERSION; 9 | import androidx.core.app.ActivityCompat; 10 | 11 | @TargetApi(16) 12 | public class PermissionHelpers { 13 | // Storage Permissions 14 | public static final int REQUEST_EXTERNAL_STORAGE = 112; 15 | private static String[] PERMISSIONS_STORAGE = { 16 | Manifest.permission.WRITE_EXTERNAL_STORAGE, 17 | Manifest.permission.READ_EXTERNAL_STORAGE 18 | }; 19 | 20 | // Mic Permissions 21 | public static final int REQUEST_MIC = 113; 22 | private static String[] PERMISSIONS_MIC = { 23 | Manifest.permission.RECORD_AUDIO 24 | }; 25 | 26 | /** 27 | * Checks if the app has permission to write to device storage
28 | * If the app does not has permission then the user will be prompted to grant permissions
29 | * Required for the {@link Context#getExternalCacheDir()}
30 | * NOTE: runs async
31 | * 32 | * @param activity to apply permissions to 33 | */ 34 | public static void verifyStoragePermissions(Context activity) { 35 | requestPermissions(activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE); 36 | } 37 | 38 | public static void verifyMicPermissions(Context activity) { 39 | requestPermissions(activity, PERMISSIONS_MIC, REQUEST_MIC); 40 | } 41 | 42 | /** 43 | * Only check. There is no prompt. 44 | * @param activity to apply permissions to 45 | * @return whether permission already granted 46 | */ 47 | public static boolean hasStoragePermissions(Context activity) { 48 | // Check if we have write permission 49 | return hasPermissions(activity, PERMISSIONS_STORAGE); 50 | } 51 | 52 | public static boolean hasMicPermissions(Context activity) { 53 | // Check if we have mic permission 54 | return hasPermissions(activity, PERMISSIONS_MIC); 55 | } 56 | 57 | // Utils 58 | 59 | /** 60 | * Shows permissions dialog
61 | * NOTE: runs async 62 | */ 63 | private static void requestPermissions(Context activity, String[] permissions, int requestId) { 64 | if (!hasPermissions(activity, permissions) && !Helpers.isGenymotion()) { 65 | if (activity instanceof Activity) { 66 | // We don't have permission so prompt the user 67 | ActivityCompat.requestPermissions( 68 | (Activity) activity, 69 | permissions, 70 | requestId 71 | ); 72 | } 73 | } 74 | } 75 | 76 | /** 77 | * Only check. There is no prompt. 78 | * @param activity to apply permissions to 79 | * @return whether permission already granted 80 | */ 81 | private static boolean hasPermissions(Context activity, String... permissions) { 82 | if (VERSION.SDK_INT >= 23) { 83 | for (String permission : permissions) { 84 | int result = ActivityCompat.checkSelfPermission(activity, permission); 85 | if (result != PackageManager.PERMISSION_GRANTED) { 86 | return false; 87 | } 88 | } 89 | } 90 | 91 | return true; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/ime/EventLogTags.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.ime; 2 | 3 | import android.util.EventLog; 4 | 5 | public class EventLogTags { 6 | public static final int TIME_LEANBACK_IME_INPUT = 270900; 7 | public static final int TOTAL_LEANBACK_IME_BACKSPACE = 270902; 8 | 9 | public static void writeTimeLeanbackImeInput(long time, long duration) { 10 | EventLog.writeEvent(TIME_LEANBACK_IME_INPUT, new Object[]{time, duration}); 11 | } 12 | 13 | public static void writeTotalLeanbackImeBackspace(int count) { 14 | EventLog.writeEvent(TOTAL_LEANBACK_IME_BACKSPACE, count); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/ime/LeanbackSuggestionsFactory.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.ime; 2 | 3 | import android.inputmethodservice.InputMethodService; 4 | import android.text.InputType; 5 | import android.text.TextUtils; 6 | import android.util.Log; 7 | import android.view.inputmethod.CompletionInfo; 8 | import android.view.inputmethod.EditorInfo; 9 | import com.liskovsoft.leankeykeyboard.R; 10 | 11 | import java.util.ArrayList; 12 | 13 | public class LeanbackSuggestionsFactory { 14 | private static final String TAG = "LbSuggestionsFactory"; 15 | private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); // Use short text tag to fix "Log tag exceeds limit of 23 characters" 16 | private static final int MODE_AUTO_COMPLETE = 2; 17 | private static final int MODE_DEFAULT = 0; 18 | private static final int MODE_DOMAIN = 1; 19 | private InputMethodService mContext; 20 | private int mMode; 21 | private int mNumSuggestions; 22 | private final ArrayList mSuggestions = new ArrayList<>(); 23 | 24 | public LeanbackSuggestionsFactory(InputMethodService context, int numSuggestions) { 25 | mContext = context; 26 | mNumSuggestions = numSuggestions; 27 | } 28 | 29 | public void clearSuggestions() { 30 | mSuggestions.clear(); 31 | mSuggestions.add(null); // make room for user input, see LeanbackKeyboardContainer.addUserInputToSuggestions 32 | } 33 | 34 | public void createSuggestions() { 35 | clearSuggestions(); 36 | if (mMode == MODE_DOMAIN) { 37 | String[] domains = mContext.getResources().getStringArray(R.array.common_domains); 38 | int totalDomains = domains.length; 39 | 40 | for (int i = 0; i < totalDomains; ++i) { 41 | String domain = domains[i]; 42 | mSuggestions.add(domain); 43 | } 44 | } 45 | 46 | } 47 | 48 | public ArrayList getSuggestions() { 49 | return mSuggestions; 50 | } 51 | 52 | public void onDisplayCompletions(CompletionInfo[] infos) { 53 | createSuggestions(); 54 | int len; 55 | if (infos == null) { 56 | len = 0; 57 | } else { 58 | len = infos.length; 59 | } 60 | 61 | for (int i = 0; i < len && mSuggestions.size() < mNumSuggestions && !TextUtils.isEmpty(infos[i].getText()); ++i) { 62 | mSuggestions.add(i, infos[i].getText().toString()); 63 | } 64 | 65 | if (DEBUG) { 66 | for (len = 0; len < mSuggestions.size(); ++len) { 67 | Log.d(TAG, "completion " + len + ": " + mSuggestions.get(len)); 68 | } 69 | } 70 | 71 | } 72 | 73 | public void onStartInput(EditorInfo info) { 74 | mMode = MODE_DEFAULT; 75 | if ((info.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { 76 | mMode = MODE_AUTO_COMPLETE; 77 | } 78 | 79 | switch (LeanbackUtils.getInputTypeClass(info)) { 80 | case InputType.TYPE_CLASS_TEXT: 81 | switch (LeanbackUtils.getInputTypeVariation(info)) { 82 | case InputType.TYPE_DATETIME_VARIATION_TIME: 83 | case InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS: 84 | mMode = MODE_DOMAIN; 85 | return; 86 | default: 87 | return; 88 | } 89 | default: 90 | } 91 | } 92 | 93 | public boolean shouldSuggestionsAmend() { 94 | return mMode == MODE_DOMAIN; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/ime/voice/SpeechLevelSource.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.ime.voice; 2 | 3 | public class SpeechLevelSource { 4 | private volatile int mSpeechLevel; 5 | 6 | public int getSpeechLevel() { 7 | return mSpeechLevel; 8 | } 9 | 10 | public boolean isValid() { 11 | return mSpeechLevel > 0; 12 | } 13 | 14 | public void reset() { 15 | mSpeechLevel = -1; 16 | } 17 | 18 | public void setSpeechLevel(int speechLevel) { 19 | if (speechLevel >= 0 && speechLevel <= 100) { 20 | mSpeechLevel = speechLevel; 21 | } else { 22 | throw new IllegalArgumentException(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/receiver/RestartServiceReceiver.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.receiver; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.util.Log; 7 | import com.liskovsoft.leankeyboard.ime.LeanbackImeService; 8 | 9 | public class RestartServiceReceiver extends BroadcastReceiver { 10 | private static final String TAG = RestartServiceReceiver.class.getSimpleName(); 11 | 12 | @Override 13 | public void onReceive(Context context, Intent intent) { 14 | sendMessageToService(context); 15 | //restartService(context); 16 | } 17 | 18 | private void sendMessageToService(Context context) { 19 | Log.d(TAG, "Sending restart message to the service"); 20 | Intent intent = new Intent(context, LeanbackImeService.class); 21 | intent.putExtra(LeanbackImeService.COMMAND_RESTART, true); 22 | context.startService(intent); 23 | } 24 | 25 | private void restartService(Context context) { 26 | System.exit(0); 27 | } 28 | } -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/receiver/TextUpdateReceiver.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.receiver; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.util.Log; 7 | 8 | public class TextUpdateReceiver extends BroadcastReceiver { 9 | private static final String TAG = TextUpdateReceiver.class.getSimpleName(); 10 | 11 | @Override 12 | public void onReceive(Context context, Intent intent) { 13 | Log.d(TAG, intent.toUri(0)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/utils/LocaleUtility.java: -------------------------------------------------------------------------------- 1 | package com.liskovsoft.leankeyboard.utils; 2 | 3 | import android.content.Context; 4 | import android.content.res.Configuration; 5 | import android.os.Build.VERSION; 6 | import android.util.Log; 7 | 8 | import java.util.Locale; 9 | 10 | public class LocaleUtility extends LocaleScript { 11 | private static final String TAG = LocaleUtility.class.getSimpleName(); 12 | 13 | public static Locale getSystemLocale(Context context) { 14 | return getSystemLocale(context.getResources().getConfiguration()); 15 | } 16 | 17 | public static void setSystemLocale(Context context, Locale locale) { 18 | setSystemLocale(context.getResources().getConfiguration(), locale); 19 | } 20 | 21 | @SuppressWarnings("deprecation") 22 | public static void setSystemLocale(Configuration config, Locale locale) { 23 | if (VERSION.SDK_INT < 24) { 24 | config.locale = locale; 25 | } else { 26 | config.setLocale(locale); 27 | } 28 | } 29 | 30 | @SuppressWarnings("deprecation") 31 | public static Locale getSystemLocale(Configuration config) { 32 | if (VERSION.SDK_INT < 24) { 33 | return config.locale; 34 | } else { 35 | return config.getLocales().get(0); 36 | } 37 | } 38 | 39 | /** 40 | * Modern Solution 41 | */ 42 | @SuppressWarnings("deprecation") 43 | public static void forceLocaleOld(Context ctx, Locale locale) { 44 | Locale.setDefault(locale); 45 | Configuration config = ctx.getResources().getConfiguration(); 46 | LocaleUtility.setSystemLocale(config, locale); 47 | ctx.getResources().updateConfiguration(config, 48 | ctx.getResources().getDisplayMetrics()); 49 | } 50 | 51 | public static void switchRuLocale(Context ctx) { 52 | Log.d(TAG, "Trying to switch locale back and forward"); 53 | Locale savedLocale = Locale.getDefault(); 54 | LocaleUtility.forceLocaleOld(ctx, new Locale("ru")); 55 | LocaleUtility.forceLocaleOld(ctx, savedLocale); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/java/com/liskovsoft/leankeyboard/widgets/DialogTitle.java: -------------------------------------------------------------------------------- 1 | // Useful links: 2 | // https://android.googlesource.com/platform/frameworks/base/+/de47f1c358c8186ff3e14b887d5869f69b9a9d6c/core/java/com/android/internal/widget/DialogTitle.java 3 | // com.android.internal.widget.DialogTitle: https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/layout/alert_dialog.xml 4 | // https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/app/AlertController.java 5 | // : https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/res/res/values/attrs.xml 6 | 7 | 8 | package com.liskovsoft.leankeyboard.widgets; 9 | 10 | import android.content.Context; 11 | import android.content.res.TypedArray; 12 | import android.text.Layout; 13 | import android.util.AttributeSet; 14 | import android.util.TypedValue; 15 | import androidx.appcompat.widget.AppCompatTextView; 16 | import com.liskovsoft.leankeykeyboard.R; 17 | 18 | /** 19 | * Used by dialogs to change the font size and number of lines to try to fit 20 | * the text to the available space. 21 | */ 22 | public class DialogTitle extends AppCompatTextView { 23 | 24 | public DialogTitle(Context context, AttributeSet attrs, 25 | int defStyle) { 26 | super(context, attrs, defStyle); 27 | } 28 | public DialogTitle(Context context, AttributeSet attrs) { 29 | super(context, attrs); 30 | } 31 | public DialogTitle(Context context) { 32 | super(context); 33 | } 34 | 35 | @Override 36 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 37 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 38 | final Layout layout = getLayout(); 39 | if (layout != null) { 40 | final int lineCount = layout.getLineCount(); 41 | if (lineCount > 0) { 42 | final int ellipsisCount = layout.getEllipsisCount(lineCount - 1); 43 | if (ellipsisCount > 0) { 44 | setSingleLine(false); 45 | 46 | TypedArray a = getContext().obtainStyledAttributes(null, 47 | R.styleable.TextAppearance, 48 | android.R.attr.textAppearanceMedium, 49 | android.R.style.TextAppearance_Medium); 50 | final int textSize = a.getDimensionPixelSize( 51 | R.styleable.TextAppearance_textSize, 52 | (int) (20 * getResources().getDisplayMetrics().density)); 53 | final int textColor = a.getColor( 54 | R.styleable.TextAppearance_textColor, 0xffffffff); 55 | // textSize is already expressed in pixels 56 | setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); 57 | setTextColor(textColor); 58 | setMaxLines(2); 59 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-hdpi-v4/ic_voice_available.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-hdpi-v4/ic_voice_available.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-hdpi-v4/ic_voice_focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-hdpi-v4/ic_voice_focus.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-hdpi-v4/ic_voice_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-hdpi-v4/ic_voice_off.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-hdpi-v4/ic_voice_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-hdpi-v4/ic_voice_recording.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-hdpi-v4/key_selector.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-hdpi-v4/key_selector.9.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-hdpi-v4/touch_selector.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-hdpi-v4/touch_selector.9.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-hdpi-v4/vs_reactive_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-hdpi-v4/vs_reactive_dark.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-hdpi-v4/vs_reactive_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-hdpi-v4/vs_reactive_light.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-mdpi-v4/ic_voice_available.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-mdpi-v4/ic_voice_available.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-mdpi-v4/ic_voice_focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-mdpi-v4/ic_voice_focus.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-mdpi-v4/ic_voice_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-mdpi-v4/ic_voice_off.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-mdpi-v4/ic_voice_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-mdpi-v4/ic_voice_recording.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-mdpi-v4/key_selector.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-mdpi-v4/key_selector.9.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-mdpi-v4/touch_selector.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-mdpi-v4/touch_selector.9.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-mdpi-v4/vs_reactive_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-mdpi-v4/vs_reactive_dark.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-mdpi-v4/vs_reactive_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-mdpi-v4/vs_reactive_light.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_accent_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_accent_close.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_alphabet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_alphabet.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_clipboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_clipboard.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_delete.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_left_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_left_arrow.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_right_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_right_arrow.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_lock_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_lock_on.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_lock_on_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_lock_on_dark.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_lock_on_dark2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_lock_on_dark2.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_lock_on_dark3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_lock_on_dark3.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_lock_on_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_lock_on_white.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_off.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_shift_on.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_space.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_space.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_symbols.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_symbols.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_voice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_voice.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_ime_world.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/ic_launcher.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-nodpi-v4/key_selector_square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-nodpi-v4/key_selector_square.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-xhdpi-v4/ic_voice_available.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-xhdpi-v4/ic_voice_available.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-xhdpi-v4/ic_voice_focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-xhdpi-v4/ic_voice_focus.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-xhdpi-v4/ic_voice_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-xhdpi-v4/ic_voice_off.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-xhdpi-v4/ic_voice_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-xhdpi-v4/ic_voice_recording.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-xhdpi-v4/key_selector.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-xhdpi-v4/key_selector.9.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-xhdpi-v4/touch_selector.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-xhdpi-v4/touch_selector.9.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-xhdpi-v4/vs_reactive_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-xhdpi-v4/vs_reactive_dark.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-xhdpi-v4/vs_reactive_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-xhdpi-v4/vs_reactive_light.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-xxhdpi-v4/key_selector.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-xxhdpi-v4/key_selector.9.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable-xxhdpi-v4/touch_selector.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuliskov/LeanKeyboard/b35f3acf0a9b7e866d13a64ce6158ed1d15a5ad1/leankeykeyboard/src/main/res/drawable-xxhdpi-v4/touch_selector.9.png -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable/selector_caps_shift.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable/vs_micbtn_off_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable/vs_micbtn_on_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/drawable/vs_micbtn_rec_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/layout/activity_kb_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /leankeykeyboard/src/main/res/layout/candidate.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 |