commit 562173f34de2b578203b9393beb48f7e2a272c98 Author: litingting Date: Fri Jul 26 20:18:59 2024 +0800 V1.0.0(1) com.kb.love.keyboard.theme diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/LoveKeyBoard.jks b/app/LoveKeyBoard.jks new file mode 100644 index 0000000..b3f47c2 Binary files /dev/null and b/app/LoveKeyBoard.jks differ diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..1d3ef8f --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,69 @@ +import java.text.SimpleDateFormat +import java.util.Date + +plugins { + alias(libs.plugins.android.application) + id("org.jetbrains.kotlin.android") + id ("kotlin-kapt") +} +val timestamp = SimpleDateFormat("MM_dd_HH_mm").format(Date()) +android { + namespace = "com.kb.myapplication.keyboard.choose" + compileSdk = 34 + + defaultConfig { + applicationId = "com.kb.love.keyboard.theme" + minSdk = 23 + targetSdk = 34 + versionCode = 1 + versionName = "1.0.0" + setProperty("archivesBaseName", "LoveKeyBoard_v${versionName}_(${versionCode})_$timestamp") + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + buildFeatures { + viewBinding = true + } + aaptOptions.cruncherEnabled = false + aaptOptions.useNewCruncher = false +} + +dependencies { + + implementation(libs.appcompat) + implementation(libs.material) + implementation(libs.activity) + implementation(libs.constraintlayout) + testImplementation(libs.junit) + androidTestImplementation(libs.ext.junit) + androidTestImplementation(libs.espresso.core) + implementation ("com.github.bumptech.glide:glide:4.16.0") + implementation("androidx.activity:activity-compose:1.8.2") + implementation("com.google.android.material:material:1.11.0") + implementation("com.github.omicronapps:7-Zip-JBinding-4Android:Release-16.02-2.02") + implementation ("com.google.code.gson:gson:2.10.1") + + val room_version = "2.6.1" + implementation("androidx.room:room-runtime:$room_version") + annotationProcessor("androidx.room:room-compiler:$room_version") + kapt("androidx.room:room-compiler:$room_version") + implementation("androidx.room:room-ktx:$room_version") + implementation("androidx.room:room-rxjava2:$room_version") + implementation("androidx.room:room-rxjava3:$room_version") + implementation("androidx.room:room-guava:$room_version") + testImplementation("androidx.room:room-testing:$room_version") + implementation("androidx.room:room-paging:$room_version") +} \ No newline at end of file diff --git a/app/info b/app/info new file mode 100644 index 0000000..14d2b9b --- /dev/null +++ b/app/info @@ -0,0 +1,5 @@ +包名:com.kb.love.keyboard.theme +应用名:LoveKeyBoard +签名文件:LoveKeyBoard.jks +别名:LoveKeyBoardkey0 +密码:LoveKeyBoard \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..fce2e7b --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,29 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute Sourc +#-renamesourcefileattribute SourceFile +#-renamesourcefileattribute SourceFile + +-keep class com.kb.myapplication.keyboard.choose.data.KeyBoardData{ *; } +-keep class com.omicronapplications.** { *; } +-keep class net.sf.sevenzipjbinding.** { *; } +-keep class com.google.gson.reflect.TypeToken { *; } +-keep class * extends com.google.gson.reflect.TypeToken \ No newline at end of file diff --git a/app/src/androidTest/java/com/kb/myapplication/keyboard/choose/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/kb/myapplication/keyboard/choose/ExampleInstrumentedTest.java new file mode 100644 index 0000000..72b7bf6 --- /dev/null +++ b/app/src/androidTest/java/com/kb/myapplication/keyboard/choose/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.kb.myapplication.keyboard.choose; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.kb.myapplication.keyboard.choose", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..91aaf92 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/keyboard.json b/app/src/main/assets/keyboard.json new file mode 100644 index 0000000..1fa5edf --- /dev/null +++ b/app/src/main/assets/keyboard.json @@ -0,0 +1,814 @@ +{ + "list": [ + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/0cd3014dfe1299673a425ebc66ec2ba3.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/21858a3a2b1370dd2dcdacf4289046da.jpg", + "title": "Love Parrots", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/05cdbfe6c9781ad45af02e2a1fe1656c.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/322a787af26b11c6b7954b8ba4490bdc.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/23af1dd3335933ea0b0caa0ca4770ce6.jpg", + "title": "Sunset Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/4facae6abdb7bf01743cd971a9017b52.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/60d09cb601d85f74a8689c7ea8db4b38.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/635dcd5b39d67d31afe5527419e33b9f.jpg", + "title": "Angel Devil Hearts", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/0a3d998d998a9cf3f3ccfd6bef7b16cf.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/98fd518bda7fabda7faa93b151768d15.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/d0a266b474469b3c2332352a7262ab06.jpg", + "title": "Glitter Rainbow Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/b8ee85deca13b494488c339af09afc22.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/1ce53c34b35bf78d72b919e5194c7413.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/164cb1a1c461be5cc5fda03dd0206654.jpg", + "title": "Purple Love Diamond", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/afcaab63c0a30297d85f2243061aaba4.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/c5951c713f76a16db46119d4c38e381f.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/795d371368577bd42c1cb516b55982f0.jpg", + "title": "Romantic Heart Roses", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/29e297b50cbdf05204bd27485359643c.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/756349e863ff4719a2b0fd8899dda4ce.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/1d154c71316e7c59e3b0084ab5286c88.jpg", + "title": "Sun Moon Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/a7f4b339bb79ae371a7beae5a9afaff1.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/177ef878ccac5b1c62950ef530616379.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/48aa3f6963a0052f34b976c36d2ade21.jpg", + "title": "Red Valentine Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/db83f68e68cd0497716dc046d715b7d9.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/f345a4977b9b62e43413a9ce2c18323d.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/f9d5808fc0a119cdbf1aacf242c4b74b.jpg", + "title": "Pink Doodle Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c7aa936e42c622732cbf6b2340f2e422.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/0e50d33331b1ca53732164241b301cb2.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/d0dd3045d8097f0eb782a4c494f9e05b.jpg", + "title": "Puppy Kitty Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c424b4120ff33d2ea4f87e098a5302dd.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/cdeb7ac588ffd351a1cf28eef1377f29.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/8bee8fa2ce265a3e12477d89f86014a4.jpg", + "title": "Red 3D Hearts", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/22c56f5cfa3e40561a5cc3e270791907.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/26fb1dd3ed3b885dbff1f6c26b322416.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/2dab2458f6da3ffc9f71ee8f9e33b428.jpg", + "title": "Blue Love Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/fdb57f770b282269bb242f0b52ccbe28.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/2e4f96492a02ed12f231b39e75619496.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/edb07e0e247100d146d64f635f41a28c.jpg", + "title": "Pink Love Mirror", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/748ddd6cb623c0f4676f348bd115ebb2.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/bc5213434d6c0362814a25f1a934fd5a.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/13048bcbe6b1ba377cefbe790660f51e.jpg", + "title": "Love Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/b05cda047a56286ddb3d8f4a9aa52fd7.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/e3fc1c83f59179702fbcb7a64c08d2d7.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/5c5c6a01a0b3a4805b13b6c33ffa79ca.jpg", + "title": "Sparkle Neon Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/a882bc3d4312022446ef29674543352b.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/e6848e37732e25e37ea80eee5130c08d.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/8a9ef0cdbc04f4dc5210a125b58e9a7e.jpg", + "title": "Glitter Heart Coral", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/2ff33d571b054fe99e4dd4cfc687e6bd.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/6ba97361c79a9639d3c6099e219c2b43.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/97a1d4230c053cec2a187d9c39e5b449.jpg", + "title": "Love Heart Neon", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c96cedb306c2b6295e902a42a3539c27.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/c8f1353c226c502ce1cef770103cbc1c.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/69c5c402b5568e47d9ac36e174c26b77.jpg", + "title": "Aesthetic Sunset", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/33877b62fc70196ebcbf14a734fc995a.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/ff93f73a242d8391ad44f65f2866a9e9.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/f04768a2b777d7f168895923af8aef2e.jpg", + "title": "Neon Love Light", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/ab2c4ad6e6312d78ddb5407e31c1f641.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/9a8f1b966039fa110cce4c86a2e3edf5.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/896bb09a18d114841fc32483e752b2bf.jpg", + "title": "Cute Kitten Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/3d940466fa31e30df1c60f80c2b2c79b.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/6b2d89c2f81ca6d6a4a6cbcbecf8a39e.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/ef8fd0c3f6a4723fd092a7fd33f77494.jpg", + "title": "Graffiti Rose Pink", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/d7c58f283c8755c99d0abe8950f5c7d1.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/a05cb6aa0c4d5b4fee04a1534bc6ea04.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/580c7d0997c93ca57a6c4c62fd85d6d8.jpg", + "title": "Pink Neon Hearts", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/7aab01a381bf315210813cba67afaa0d.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/82f6ab84adc7a9f621d5a66ab07bcb87.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/3528ab9f0ec9022f1ac0b61a040a32c4.jpg", + "title": "Neon Light Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/8afbd8f60b302a69e6e7581807002626.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/4a8ceb2b8b082b744c8823fe1f34b5dc.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/581b74289fd52181777b34bc9f476b76.jpg", + "title": "Red Hearts 3D", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/7c6f0f7796761d67074749242691c46a.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/d3e38f0128ad8b2d6c19f20b536e0792.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/337c48b1d04a66c8c662fe8fac7d1f96.jpg", + "title": "Shy Love Emoji", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/73c74526b80ec6b00e4aea35b8b3cf10.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/4281984af73c48808ec381a2eb03842f.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/3f56ae964777d071c10fb82268b72360.jpg", + "title": "Lovely Birds", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/1a1eb9cb1234641b6e7ad2ec3307fd04.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/abd43be8531db0a72b1db27293454fb4.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/e74ef3977541c33c72ee00db9ad5fb7d.jpg", + "title": "Love Balloon", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/255fc373390574160e87e4cdb588e4dc.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/07351b748fa7f2ba6f3ef884002e733c.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/52dcbc054c8b8794ceaff7a6f7eb98d2.jpg", + "title": "Colorful Crystal Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/d215e2d40ab4c5638878f55c58899f54.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/d555577385bebaf3f1c9d48fe88e0998.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/435665abee707a3a7fddd5d6a61b57ab.jpg", + "title": "Cat Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/1e0139f2d561a09a6dd0d5485ddc0e05.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/a94584cb8ffc7c9fd8edc5e7f644fb62.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/80e6151a3587253513dbe6c6ffb58997.jpg", + "title": "Shining Twin Hearts", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/4a707c5c0ed8c0f75db9f2ce02f7c5c1.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/2aff11564a49dedcff9255a51228d694.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/3ada3855bfce57d155528d56d229e72c.jpg", + "title": "Love Heart Lollipop", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/0e5349b50a623e8e9cba9a2829c95682.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/bc61592ff75190347e8840cc6637f43b.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/61555a1baaad3ea85194ed431af92172.jpg", + "title": "Neon Kitten Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/553a163368a028f07ea83b381f436434.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/b39a4718a097019fa9bb91984b638d91.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/4a83f452037c1c1e0be2bbfca73613f1.jpg", + "title": "Love Kitten", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/cd69f48f9c719bc070d232808cd119b2.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/50a6b9028c17f689e980535ab33c5284.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/472e91317bc96a393695dc0e852a8625.jpg", + "title": "Love And Peace", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/8ffbe44dbe2b011c19a63ca430daab3d.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/ad0b8e69a433285a8fd9ae23e857d4ab.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/febb8cef9ae8d2e6e318bba37d1d0b3e.jpg", + "title": "Pink Love Balloons", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/5b9f3b02886fc935438448ca149fb8ed.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/a4c378e32b413949f02cd93847a764f7.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/f50c4d26af82ab8ecf2388e39602328f.jpg", + "title": "Dog Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/ed5963803a2b00d078a682dab3a1737f.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/2e5d1512f63e4c9ea2378d7a33365250.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/e467146a07ae9557ea5b493b1f6d324c.jpg", + "title": "Galaxy Marble Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/e2f7d694adf3ec22f35aa7a4ff52643a.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/ac6410743ea9048cdb299b800a26dd60.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/85698dc949cd380f1822bcf7182e8a44.jpg", + "title": "Bright Blue Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/d9176e756817915375663be035096fba.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/ecc75487e7038bd6c7dd72ea74d3d4b6.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/3ae613b256996ca888628571e074b387.jpg", + "title": "Parrot Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/37ae31adf1e9c1541cf04e99e63790d2.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/283b5e61bf797c138e19cc2e47fa718f.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/72897d23e69b92e20285f867d9e2f81d.jpg", + "title": "Love Pet Life", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/f0c78374e37a43deacb280f16cbc4e8d.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/6ab39f35c65e0e8f3ceb9397bb6fe472.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/323d398d38ab6d198aea4912376c1a9d.jpg", + "title": "Cute Bunny Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/a0bffe36ae759d94538044f645fb0a81.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/cc3169c2853c7c6ef76aa341262ab803.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/a82105f908e63a5c1fed450f855f22e1.jpg", + "title": "Neon Finger Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/a75373cf46ec40dd8c3f09a15967f417.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/44f47f5cfb02411fb4077b66c3ed058c.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/bcb7e8bf064260ce689a6473e445e08f.jpg", + "title": "Red Love Valentines", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/633eb4f7ca16374728a20eb3655abc63.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/4671747ba8117a3bff1a5af7cb3957a7.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/7495c81c2c3ca2ab97608e49667e8d30.jpg", + "title": "Rose Gold Pearls", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/0e1bb2bbfc63359656d2d9626b9cbfa4.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/dc5a25565b3cbbd7ca4759d41503e14a.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/0dea2ab904a92e76f13a9f92ebed2f57.jpg", + "title": "XOXO", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/bb4abe2a966e99ce4cc00edf66ca18b6.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/dfea248800b350c85c3b0704d59e3843.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/03314742fe2a1be29e9d500c72a39e67.jpg", + "title": "Pink Glitter Heart 2", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/93bbefb657fa054f6845387dab56ea0c.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/767ffc55088e4cc1f6026592e172894f.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/823e682de86a7df3d301e38fad16897e.jpg", + "title": "Avocado Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/32058e9dc1e0ad2c94cdc7250f5abf3c.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/3e6c4e8c4bc2184507789d738c943df0.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/be1a546d76c1a08b85547fbcda7fc136.jpg", + "title": "Pink RGB Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/5de85592a7e96862a81e56f1dae7e21f.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/6d830c6ec0ab22a851d84c37bbb9f964.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/8774e8fcc8c0dfa4089ba630c4b36092.jpg", + "title": "Neon Romantic Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/b1a2723340145b9972c46e32211738fc.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/fa652fd752b83b4be2ee795592ce8686.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/bba3f6325628052e4ad5f277c04e8782.jpg", + "title": "Love Couple Cats", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/8ef3574260b228ac18c3d942be156421.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/95459ffa27560a8d832b8e0bd68d839f.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/d14101bd18d88fe38c8926da51f5c527.jpg", + "title": "Love Heart Kpop", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/73234e4d1f8229a91085dc77e3bc01c2.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/1ec1fdf2f65f56b35bd20e3ec37d0a4d.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/1f16466b0c02d7e12e88bd852965d6b6.jpg", + "title": "Valentine Lovelight", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/1e9781ed97d96bb1ede09b4324da4666.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/2678a9d60a6deafcb0ce39611aab4ada.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/04aa21e32769749d30c107a193729ac3.jpg", + "title": "Love Penguin Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c694af4caa592c54dcaf7d0da8a373fe.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/3e396b0112a3fe5ef2bdd423418dfef1.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/cc0f081e2d2d314917fdc855f315e6ef.jpg", + "title": "Love Panda Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/579033fa6a038b04a5495a2e82632039.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/9113d3554aff19a708934018360ab389.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/0cd61f43a46d90f956e6eade6bd0caf5.jpg", + "title": "Teddy Loving Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/4414f4e03dfa1501d89e11151b4ae1db.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/ed744dce1f269d5d678bd3aee07fc142.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/46debd656f7ab1fdc2045b74defb26df.jpg", + "title": "Sparkle Glitter Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/2b7602f6dc1710c392a7fb0c0d87f3f7.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/121ffd309cf6f20cc6e54e03f2bc713b.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/5ca595c01a89db6d51c893e54e7e48c9.jpg", + "title": "Black Heartbeat", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/e89c30a80f329f04c8f770cdaf3a8b6e.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/fb68c9429c1f43e6377c1f5b4b45355d.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/fc16ae2a6687588003f42509ab3ccbea.jpg", + "title": "Red Valentine Hearts", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c1e0698ef820eb14be84697024885e7c.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/9fc4ce4bed6c72fcee3d03f726473731.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/dc3c6ea8a9a42d6af7c08cdb9a0607ea.jpg", + "title": "Bear Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/e83c5e33f8f5356178aa7de4dd6975f3.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/967541749f2f1442db1e9a23e95421a8.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/9493c05cfdb60a75bc0d6ea3651992ce.jpg", + "title": "Cute Moon Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/efc2ee720eb22b534f44656ac50d34c8.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/6ab39f35c65e0e8f3ceb9397bb6fe472.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/323d398d38ab6d198aea4912376c1a9d.jpg", + "title": "Cute Bunny Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/a0bffe36ae759d94538044f645fb0a81.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/cc3169c2853c7c6ef76aa341262ab803.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/a82105f908e63a5c1fed450f855f22e1.jpg", + "title": "Neon Finger Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/a75373cf46ec40dd8c3f09a15967f417.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/44f47f5cfb02411fb4077b66c3ed058c.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/bcb7e8bf064260ce689a6473e445e08f.jpg", + "title": "Red Love Valentines", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/633eb4f7ca16374728a20eb3655abc63.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/4671747ba8117a3bff1a5af7cb3957a7.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/7495c81c2c3ca2ab97608e49667e8d30.jpg", + "title": "Rose Gold Pearls", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/0e1bb2bbfc63359656d2d9626b9cbfa4.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/dc5a25565b3cbbd7ca4759d41503e14a.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/0dea2ab904a92e76f13a9f92ebed2f57.jpg", + "title": "XOXO", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/bb4abe2a966e99ce4cc00edf66ca18b6.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/dfea248800b350c85c3b0704d59e3843.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/03314742fe2a1be29e9d500c72a39e67.jpg", + "title": "Pink Glitter Heart 2", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/93bbefb657fa054f6845387dab56ea0c.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/767ffc55088e4cc1f6026592e172894f.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/823e682de86a7df3d301e38fad16897e.jpg", + "title": "Avocado Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/32058e9dc1e0ad2c94cdc7250f5abf3c.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/3e6c4e8c4bc2184507789d738c943df0.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/be1a546d76c1a08b85547fbcda7fc136.jpg", + "title": "Pink RGB Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/5de85592a7e96862a81e56f1dae7e21f.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/6d830c6ec0ab22a851d84c37bbb9f964.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/8774e8fcc8c0dfa4089ba630c4b36092.jpg", + "title": "Neon Romantic Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/b1a2723340145b9972c46e32211738fc.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/fa652fd752b83b4be2ee795592ce8686.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/bba3f6325628052e4ad5f277c04e8782.jpg", + "title": "Love Couple Cats", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/8ef3574260b228ac18c3d942be156421.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/95459ffa27560a8d832b8e0bd68d839f.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/d14101bd18d88fe38c8926da51f5c527.jpg", + "title": "Love Heart Kpop", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/73234e4d1f8229a91085dc77e3bc01c2.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/1ec1fdf2f65f56b35bd20e3ec37d0a4d.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/1f16466b0c02d7e12e88bd852965d6b6.jpg", + "title": "Valentine Lovelight", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/1e9781ed97d96bb1ede09b4324da4666.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/2678a9d60a6deafcb0ce39611aab4ada.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/04aa21e32769749d30c107a193729ac3.jpg", + "title": "Love Penguin Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c694af4caa592c54dcaf7d0da8a373fe.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/3e396b0112a3fe5ef2bdd423418dfef1.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/cc0f081e2d2d314917fdc855f315e6ef.jpg", + "title": "Love Panda Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/579033fa6a038b04a5495a2e82632039.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/9113d3554aff19a708934018360ab389.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/0cd61f43a46d90f956e6eade6bd0caf5.jpg", + "title": "Teddy Loving Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/4414f4e03dfa1501d89e11151b4ae1db.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/ed744dce1f269d5d678bd3aee07fc142.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/46debd656f7ab1fdc2045b74defb26df.jpg", + "title": "Sparkle Glitter Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/2b7602f6dc1710c392a7fb0c0d87f3f7.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/121ffd309cf6f20cc6e54e03f2bc713b.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/5ca595c01a89db6d51c893e54e7e48c9.jpg", + "title": "Black Heartbeat", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/e89c30a80f329f04c8f770cdaf3a8b6e.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/fb68c9429c1f43e6377c1f5b4b45355d.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/fc16ae2a6687588003f42509ab3ccbea.jpg", + "title": "Red Valentine Hearts", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c1e0698ef820eb14be84697024885e7c.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/9fc4ce4bed6c72fcee3d03f726473731.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/dc3c6ea8a9a42d6af7c08cdb9a0607ea.jpg", + "title": "Bear Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/e83c5e33f8f5356178aa7de4dd6975f3.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/967541749f2f1442db1e9a23e95421a8.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/9493c05cfdb60a75bc0d6ea3651992ce.jpg", + "title": "Cute Moon Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/efc2ee720eb22b534f44656ac50d34c8.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/dd5fbcddfdff76b7d58a1568082c9d21.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/c0c704ac8282ec17a437d2e3dd704f4c.jpg", + "title": "Sunset Lovers 2", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/a9d6762f2f8a846a5fb2f260f0c5a198.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/841d6f969f2064b467f1eaca5a0325f3.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/500e5885cd29272651b799422515cbdf.jpg", + "title": "Couple Love Story", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/3eec6ce21ffeb7c1658dd37a14f76a3f.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/fe736d082251fa6d97db8c58986cab2c.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/2098b91375ff1b51076c8c9192ddd697.jpg", + "title": "Teddy Bear Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/cfdf48db3b5058462ec3e32c465db6e2.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/10c36eb5a7a8172000ef2a154deebcb1.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/dd6579a161d6b82d9b547bcde8d02116.jpg", + "title": "Diamond Purple Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/53885d9bdb51dc6c60b95fbdcb495558.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/a64fee9a9dac129120193107e3cb231a.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/f7db9a6e3f57b0acf8ce59c8f0bed461.jpg", + "title": "Doodle Red Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/37958199700cc8d96ddad8dceda8ab80.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/4823dbbc77b6e21d154422525f4805f5.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/fc3c1e87255f20ee235af745eeb0be17.jpg", + "title": "Fairy Lights Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/47f7270d2ae94de74a5ee11b7ea3d198.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/caf8614e167ddc17487ced306c66776a.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/1c56ad42b17cb01c911c0d0d17167f97.jpg", + "title": "Pink Couple Bear", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/5490bf09d1924309238005051096807c.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/bb46509d8625dae56eed4408733322d5.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/d80d1ea5f5eda60782cbe132d0455ba9.jpg", + "title": "Lovely Red Hearts", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/e5df650faccb66e7ce224dc7e1856418.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/3adc4c3d10994ea70a010da23648104d.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/73849c532ebe3ca7f1500e791083750f.jpg", + "title": "Bear Couple Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/638fa021a26e55dbc3a96b3d17015f06.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/3f960095f31247dbc0db4ebcd31c2657.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/0013e3260579e190e0fa29e4761d5877.jpg", + "title": "Love Red Rose", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/7f49631ec32225bf8a7f8dd49c2370fb.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/0d8ae325a6ecbc356a1d3b76beca32fe.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/b40d5a5ac0c06c1b5544b1fc8f99095f.jpg", + "title": "Neon Light Rose", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/35855c73a0ee0071c5ae0f0e56357510.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/5b6fba1f3955eaae9c4bf88d2d8b9d11.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/b01a2187b9142a50183152cebbfc2c16.jpg", + "title": "Red Hearts", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/bc59e2baa61fd6840010d3851e981c81.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/b0b9567e1ae90ddeb135745b1365b5b8.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/43621e0f82a4764931cdfefb17a6e1ac.jpg", + "title": "Neon Streaks Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/91114c6c2cc25d287773d624bc1b64bc.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/68013a4751d5ab8fa799952a4c38c871.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/f082befb417770957e62417ea462332c.jpg", + "title": "True Love Roses", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/b38a26a89634807b4dfbbb06b8e1a61a.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/e2ac82ef4c9bffb97ba3000660fa569a.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/339187477dc314f27d37aa6e3d033081.jpg", + "title": "Love Birds", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/663df7425d314df83bc46b75528075e4.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/a794436515ba6cdc92bcc8d59fac7def.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/e09382ca186536d9e92ac55e9b0ff345.jpg", + "title": "Pink Heart Black", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/33bd498a8118935a64bd643e2b3f8df0.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/0068d3a3ff6c14fa4204e5b96384ae4a.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/f55e6ea21c2c0ff9264e61a75ae046e0.jpg", + "title": "Yellow Couple Lover", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/802e5f7d2fc1cadb8d19164d6cded733.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/dcdda4fc64e23afd1e78ebfa7fcd491c.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/8955fde338d34013859d8a391e4f501f.jpg", + "title": "Purple Doodle Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/9ef09792a772bc0813d31de9538c1297.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/16da56b7c6bab5dcfa5f832d956d1ca8.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/f5e2f25a24bb45f7fd348f14845ca1ef.jpg", + "title": "Bubble Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/d842b752aca13d74f01d446c9efa4dc7.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/d3c71d7c3766e441b9dbbe13bd04452e.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/6f4d665077e0a2499cf572afa5ab2cb7.jpg", + "title": "Sexy Love Lips", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/83e852b8503d697abc324800111f766c.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/cac72a50cdcbdd36119dbdc47ffac9d6.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/2a64bcda6842dcaeea8604af26874b45.jpg", + "title": "Parrots Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/3e541d8ed0bf3ed6470cd348795b9182.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/a8bc295c764c040f3bec026f9e6c6d62.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/313a5c7f756c70ebbe4aba2e3193badb.jpg", + "title": "Transparent Hearts", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/af5797dec108055a9936dd1a5ab9ecf9.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/42397e7f5caa7cfcfde15c069cfdf6b8.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/d0e92526487439b64944a456839e54c6.jpg", + "title": "Neon Red Heartbeat", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/f246376590b509c63173963c71335535.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/f488f10ec3593ed3f545770d6d386db4.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/f63666b958b6aea4137536b1d50b03fd.jpg", + "title": "Black Gold Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/36e55a59fb80a515e6f977900c08a6e1.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/770fb6d3810b764a623724d991c7775f.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/5105aa6cfc9aa2a9e3c44bbf14f3b2ae.jpg", + "title": "Purple Neon Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/bd0ed1d65feae6e0f21a56924e9b6015.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/3335bffc14452db55ffb53c11eb1b6e8.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/d63b01a6be5a46ec57c497be44936344.jpg", + "title": "USA Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/f9fe6f443a3e140b1503a21566960639.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/0f90d13aae661b3ba7236aef6628c6d1.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/80c4a8642943f4b1eb562716cc1f6068.jpg", + "title": "Fairy Lights Heart 2", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/e28ffc76f76632e34bae5bd815adbca3.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/2ff613db906187cfefbc5ee1238c948c.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/386136fdfcda7d7806ff01991cb8d51b.jpg", + "title": "Neon Hand Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/b3901b0fe1c7ff7e752a8c747a0552cc.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/33bb0254df22b4c7b8a45c8012c8507d.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/1fd21a804dae285c0d435ff01a9eb52c.jpg", + "title": "Neon Heart Lights 2", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c0995dcb1673b19ed6fcc3e89c8b54e1.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/7619668cb63a40175bbf4fc80fa6bf39.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/d2420b778f5dc024858cdcec9e0b53e6.jpg", + "title": "Love Birds Couple", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/e843ad02ed8c058bf2dbf3c42f79935f.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/6b5ba0a920158a3a8c0b3d8fdb98b717.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/f135b1a8cb6aafbfa28dfdc0459b1fe2.jpg", + "title": "Cactus Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/44dd8646e8a7cfb63639bd18ecc9d0d5.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/f12701a341921f6788b87bb1f8cd7e64.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/4fcfc083c377b653a298df082f4b4028.jpg", + "title": "Cute Avocado Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/65455c53286533a1b7de336d0fb256fd.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/88d1f4f88ce82925957905c51cf9aa26.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/157d372d6ebd87ec10d0f9d31f1f2e1e.jpg", + "title": "Cross Heartbeat", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/916370723b3b60f62efae752d7591039.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/005d254e1b2f675723c0eca69a5ae020.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/0cc53f596a170e545ec14e5a62593bbf.jpg", + "title": "Rose Gold Marble Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c33e66e6281de12ba2bd9459ca5ddfcd.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/cac9728dcb632c387d90ad911a737e72.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/92cd223af4b01e54cd1b5e9b31cbcc70.jpg", + "title": "Neon Pink Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/6db73f2c4286ff6d8ae767f2bfd3c8f9.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/2254766caef14736d7a783b84f249e64.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/1a0596d424cf013bab4b19cfaf72eb8e.jpg", + "title": "Emoji Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/dd7c5fde1bc76b02be5dc566225f8754.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/facc6aded38e054aba98a2c8839986d3.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/7fe6e38b38598ab04e9332ccd3b0c281.jpg", + "title": "Glitter Emoji Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/bc1c3e41a6029d01793cef5cd5a4e62d.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/23ae98a16bc696d939821d376bdcec5a.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/3a77de6bf075e8ae257c866dec46333a.jpg", + "title": "Fairy Lights Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/b26a10ebcfc9bf28ce99b91c10139afd.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/905895c61803623e17888ea655aa4ff7.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/5a3bbd4795fc15bec6075114ea22c185.jpg", + "title": "Grim Reaper Skull Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c79357f5d02ec6a1b4b128ec622e578e.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/ffbb4be389b0557885f07f1df5a5594b.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/32eb87ed6a725286b5fca63f91e7c939.jpg", + "title": "Neon Blue Heartbeat", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/b97abba35134ff1de476bfc399ae68cf.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/3ecb0be64972dc7d1cbaf8c35eba4cbe.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/86049b96b196c0894ad07c64db1be4b8.jpg", + "title": "Love You Emoji", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/082482741d8c81290b276355c3dc4b1d.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/98e99f52957a700c33b0bb598b09cf16.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/7cb0e3a0978acfbd5b1a44ccfd8129c0.jpg", + "title": "Doodle Pink Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/6bf53db168e318f415b80fdcd9ebd525.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/5f0415e98234e3c81e1b939ed6d247d1.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/4e46c11a200b664fccefc86499e36ec6.jpg", + "title": "Love Sweets", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/8d7b061b994b4615d4b9d202e2db8646.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/1c717f202676dd3a3388e79a8e02e6d1.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/66fcc417a0d8fbd75c376b9eec2453ae.jpg", + "title": "Lovely Ragged Bear", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/51f4c9c699b7db37ee6e18e57ac884b4.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/762f005d7b9a01193a35626201223f31.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/522b79ce9b60fd4da075ebfc81621e40.jpg", + "title": "Cute Birds Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/6a29220be7995facaee31c8904ff7d2d.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/7401f32670f06f0249cb7202ccd23685.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/d71c9ab6f0b2bf10aa156f42362e1c0f.jpg", + "title": "Neon Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/af977a101d7dea4c4e7877e1dd5b8d69.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/aa479881b7b82941d275e0e0c1c35cc2.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/37c7d921e85672618823c1c94b7390ad.jpg", + "title": "Valentine Hearts", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/c0f6ee79e5601dd0540616cbbd51ac98.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/54b9b431a24455df198de8f5826560aa.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/6bd55ffc38c331492f8d778229a8ebb2.jpg", + "title": "Pastel Blue Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/bd9d2e985ec8d01b869f584cd2c78432.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/8e472772f568cc79ffff4a4b2e3afc77.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/8a77100efe5f2bb872122c1a53551ea9.jpg", + "title": "Neon Heart Wings", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/8745dbdb9359c1782561b522c0aae5da.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/b3ab689aaf812a61fd7a4efdf66e0be1.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/edc8f72de11ab73f7c63ff2d6e866b2b.jpg", + "title": "Love Pink Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/a4dbc7a8724ffee17464f51fc9f99b43.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/8c42c7acb0606eedb6a2b18270a06c83.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/0f6a8ff31c981e514c1962a54fbe5b7f.jpg", + "title": "Pink Love Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/7307d616bbf33111ac2efed0ce2fb16a.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/5fa2c51cab09488a4ae1070924c12cc3.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/89f26e6d81a3edc29bc1d39a87e949dd.jpg", + "title": "Rose Gold Heart", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/eb7fd32f8f3f82d43b5b01522a3e31e6.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/90717cd2ea4c240b08a51e49aeb3d764.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/9e4f0e11222bd3102d146c3af5b863a2.jpg", + "title": "Sweet Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/40378b72ad77ee8f8644e7c68ef5b220.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/357accac25c7e5bfe4b25470d1e90169.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/dc5f22ebb04336f927c0f59c68343aef.jpg", + "title": "Lovely Teddy", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/bd34f0ff89109933f97bd4962abb74e7.7z" + }, + { + "preview": "https://resource-sg-public.lux-ad.com/keyboard/0c5d3e19ef62423528f5fc477b689983.webp", + "thumb": "https://resource-sg-public.lux-ad.com/keyboard/69849b2c5d44cf0441d408aae2e799ff.jpg", + "title": "Rose Love", + "zipUrl": "https://resource-sg-public.lux-ad.com/keyboard/205ac8d389c0997a03a9fd239d7797f7.7z" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/myfront.ttf b/app/src/main/assets/myfront.ttf new file mode 100644 index 0000000..a26ee85 Binary files /dev/null and b/app/src/main/assets/myfront.ttf differ diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/LoveKeyBoard.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/LoveKeyBoard.java new file mode 100644 index 0000000..98f1d0f --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/LoveKeyBoard.java @@ -0,0 +1,27 @@ +package com.kb.myapplication.keyboard.choose; + +import android.app.Application; +import android.util.Log; + +import com.kb.myapplication.keyboard.choose.data.KeyBoardData; +import com.kb.myapplication.keyboard.choose.room.LikeDataEntity; +import com.kb.myapplication.keyboard.choose.value.MyValues; + +import java.util.ArrayList; +import java.util.List; + +public class LoveKeyBoard extends Application { + + public static List loveDataList= new ArrayList<>(); + + @Override + public void onCreate() { + super.onCreate(); + MyValues.app = this; + List loveData = MyTools.parseJson(this); + if(loveData != null){ + loveDataList = loveData; + Log.d("---loveDataList","----loveDataList"+loveDataList.size()); + } + } +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/MyTools.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/MyTools.java new file mode 100644 index 0000000..2bad56f --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/MyTools.java @@ -0,0 +1,266 @@ +package com.kb.myapplication.keyboard.choose; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.StateListDrawable; +import android.provider.Settings; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.kb.myapplication.keyboard.choose.LoveKeyBoard; +import com.kb.myapplication.keyboard.choose.activity.MainActivity; +import com.kb.myapplication.keyboard.choose.data.KeyBoardData; +import com.kb.myapplication.keyboard.choose.listener.DownloadZipListener; +import com.kb.myapplication.keyboard.choose.listener.Downloadfilezip; +import com.kb.myapplication.keyboard.choose.value.MyValues; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import net.sf.sevenzipjbinding.ArchiveFormat; +import net.sf.sevenzipjbinding.IInArchive; +import net.sf.sevenzipjbinding.SevenZip; +import net.sf.sevenzipjbinding.SevenZipException; +import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; +import net.sf.sevenzipjbinding.impl.RandomAccessFileOutStream; +import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem; + +public class MyTools { + private static String Name = "shared_name"; + + private static final SharedPreferences sharedPreferences = MyValues.app.getSharedPreferences(Name,Context.MODE_PRIVATE); + private static final SharedPreferences.Editor editor = sharedPreferences.edit(); + private static ExecutorService executorService; + + //Parse the custom JSON file + public static List parseJson(Context context) { + StringBuilder sb = new StringBuilder(); + try { + InputStream open = context.getAssets().open("keyboard.json"); + BufferedReader br = new BufferedReader(new InputStreamReader(open)); + String next = ""; + while (null != (next = br.readLine())) { + sb.append(next); + } + String trim = sb.toString().trim(); + return parseJsonString(trim); + + } catch (IOException ioException) { + return null; + } + + } + private static List parseJsonString(String jsonString) { + List myDataArrayList = new ArrayList<>(); + try { + JSONObject string1 = new JSONObject(jsonString); + JSONArray list = string1.getJSONArray("list"); + for (int i = 0; i < list.length(); i++) { + KeyBoardData loveData = new KeyBoardData(); + JSONObject item = list.getJSONObject(i); + String preview = item.getString("preview"); + String thumb = item.getString("thumb"); + String title = item.getString("title"); + String zipUrl = item.getString("zipUrl"); + loveData.setPreview(String.valueOf(preview)); + loveData.setThumb(thumb); + loveData.setTitle(title); + loveData.setZipUrl(zipUrl); + myDataArrayList.add(loveData); + } + return myDataArrayList; + } catch (JSONException jsonException) { + + return null; + } + } + + //sumbit a work to ExcutorService. + public static void RunIO(Runnable work){ + getExecutorService().execute(work); + } + private static ExecutorService getExecutorService(){ + if (executorService == null){ + executorService = Executors.newSingleThreadExecutor();//单线程处理 + } + return executorService; + } + + //open inputmethod + private static InputMethodManager inputMethodManager = (InputMethodManager) MyValues.app.getSystemService(Context.INPUT_METHOD_SERVICE); + + public static void GotoFistSetting(Context context){ + Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS); + context.startActivity(intent); + } + public static boolean FirstSetting(){ + for(InputMethodInfo inputMethodInfo : inputMethodManager.getEnabledInputMethodList()){ + if (inputMethodInfo.getId().startsWith(MyValues.app.getPackageName())){ + return true; + } + } + return false; + } + + //choose this inputmethod as default inputmethod. + public static void GotoSecondSetting(){ + inputMethodManager.showInputMethodPicker(); + } + public static boolean SecondSetting() { + String string = Settings.Secure.getString(MyValues.app.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); + if(string.startsWith(MyValues.app.getPackageName())) { + return true; + } else { + return false; + } + } + + //download the resource picture + public static void DownLoadResourceZip(String url, Context context, DownloadZipListener downloadZip){ + Glide.with(context) + .asFile() + .load(url) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target target, boolean isFirstResource) { + downloadZip.downloadziplistener(false,null); + return false; + } + + @Override + public boolean onResourceReady(@NonNull File resource, @NonNull Object model, Target target, @NonNull DataSource dataSource, boolean isFirstResource) { + downloadZip.downloadziplistener(true,resource); + return false; + } + }).preload(); + } + + public static void OnLoadFileZip(String resourcePath, File resource, Downloadfilezip loadfile){ + if (!resource.exists()) { + loadfile.downloadfilezip(false,""); + return; + } + String itemfilepath = ""; + RandomAccessFileOutStream randomAccessFileOutStream = null; + IInArchive openInArchive; + RandomAccessFileInStream randomAccessFileInStream; + try { + randomAccessFileInStream = new RandomAccessFileInStream(new RandomAccessFile(resource, "r")); + openInArchive = SevenZip.openInArchive( + ArchiveFormat.SEVEN_ZIP, + randomAccessFileInStream + ); + + ISimpleInArchiveItem[] archiveItems = openInArchive.getSimpleInterface().getArchiveItems(); + for (int d = 0; d < archiveItems.length; d++) { + ISimpleInArchiveItem simple = archiveItems[d]; + File file = new File(resourcePath, simple.getPath()); + if (!simple.isFolder()) { + randomAccessFileOutStream = new RandomAccessFileOutStream(new RandomAccessFile(file, "rw")); + simple.extractSlow(randomAccessFileOutStream); + itemfilepath = file.getPath(); + + } else { + boolean mkdirs = file.mkdirs(); + } + } + randomAccessFileInStream.close(); + openInArchive.close(); + if (randomAccessFileOutStream != null) { + randomAccessFileInStream.close(); + } + int res = itemfilepath.indexOf("res"); + String substring = itemfilepath.substring(0, res + 3); + loadfile.downloadfilezip(true, substring); + + } catch (FileNotFoundException | SevenZipException e) { + loadfile.downloadfilezip(false, ""); + + } catch (IOException e) { + loadfile.downloadfilezip(false, ""); + throw new RuntimeException(e); + } + } + + public static StateListDrawable getStatus(Drawable draw, Drawable drawPress) { + StateListDrawable stateListDrawable = new StateListDrawable(); + stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, drawPress); + stateListDrawable.addState(new int[]{}, draw); + return stateListDrawable; + } + + public static String parseString(File file) { + StringBuilder sb = new StringBuilder(); + try { + BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + String next = ""; + while (null != (next = br.readLine())) { + sb.append(next); + } + String trim = sb.toString().trim(); + return trim; + + } catch (IOException ioException) { + + return null; + } + + } + + + public static void saveKeyboardSkin(String resDirPath) { + editor.putString(Name, resDirPath);//存储 + editor.apply(); + } + + public static String getKeyboardSkin() { + + return sharedPreferences.getString(Name, "");//读取,默认为空 + }//读取 + + public static String getBoardSkinPathByName(String name) { + + return sharedPreferences.getString(name, ""); + } + + public static void saveBoardSkinByName(String name, String resDirPath) { + editor.putString(name, resDirPath); + editor.apply(); + } + + + public static int dpToPx(int dp, Context context) { + float density = context.getResources().getDisplayMetrics().density; + return (int) (dp * density); + } + + public static float spToPpx(Float values, Context context) { + float scale = context.getResources().getDisplayMetrics().scaledDensity; + return values * scale; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/MyWork.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/MyWork.java new file mode 100644 index 0000000..9ba9431 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/MyWork.java @@ -0,0 +1,176 @@ +package com.kb.myapplication.keyboard.choose; + +import android.inputmethodservice.InputMethodService; +import android.os.SystemClock; +import android.view.LayoutInflater; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.LinearLayout; + +import com.kb.myapplication.keyboard.choose.base.KeyBoard; +import com.kb.myapplication.keyboard.choose.base.LoveKeyBoardView; +import com.kb.myapplication.keyboard.choose.base.MyLoveKeyBoardView; + +import java.util.List; + +public class MyWork extends InputMethodService implements LoveKeyBoardView.OnKeyboardActionListener { + private long last_click = -1L; + private boolean press_double = false; + private int[] ViewType = new int[3]; + private MyLoveKeyBoardView myLoveKeyBoardView; + @Override + public View onCreateInputView() { + ViewType[0] = R.xml.board_view_one; + ViewType[1] = R.xml.board_view_two; + ViewType[2] = R.xml.board_view_three; + View view = LayoutInflater.from(this).inflate(R.layout.my_input_view,null,false); + myLoveKeyBoardView = (MyLoveKeyBoardView) view.findViewById(R.id.my_keyboard_input); + myLoveKeyBoardView.setPreviewEnabled(false); + myLoveKeyBoardView.setKeyboard(new KeyBoard(this,ViewType[0])); + myLoveKeyBoardView.setOnKeyboardActionListener(this); + return view; + } + + @Override + public void onWindowShown() { + super.onWindowShown(); + myLoveKeyBoardView.updateConfigView(this); + } + + @Override + public void onPress(int primaryCode) { + if(primaryCode == KeyBoard.KEYCODE_SHIFT) { + if (SystemClock.elapsedRealtime() - last_click < 300) { + press_double = true; + } + last_click = SystemClock.elapsedRealtime(); + } + } + + @Override + public void onRelease(int primaryCode) { + + } + + @Override + public void onKey(int primaryCode, int[] keyCodes) { + switch (primaryCode) { + case KeyBoard.KEYCODE_SHIFT: + int shiftStatus = myLoveKeyBoardView.getShift_status(); + KeyBoard keyboard = myLoveKeyBoardView.getKeyboard(); + + switch (shiftStatus){ + case 0: + if(press_double){ + myLoveKeyBoardView.setShift_status(2); + }else { + myLoveKeyBoardView.setShift_status(1); + } + switchViewData(true,keyboard); + myLoveKeyBoardView.setKeyboard(keyboard); + break; + case 1: + if(press_double){ + myLoveKeyBoardView.setShift_status(2); + }else { + switchViewData(false,keyboard); + myLoveKeyBoardView.setShift_status(0); + } + myLoveKeyBoardView.setKeyboard(keyboard); + break; + case 2: + myLoveKeyBoardView.setShift_status(0); + switchViewData(false,keyboard); + myLoveKeyBoardView.setKeyboard(keyboard); + break; + } + break; + case KeyBoard.KEYCODE_SHIFT_123: + changeView(2); + break; + case KeyBoard.KEYCODE_SHIFT_SYMBOL: + changeView(1); + break; + case KeyBoard.KEYCODE_DELETE: + getCurrentInputConnection().deleteSurroundingText(1, 0); + break; + case KeyBoard.KEYCODE_DONE: + getCurrentInputConnection().performEditorAction(EditorInfo.IME_ACTION_SEARCH); + break; + case KeyBoard.KEYCODE_MODE_CHANGE: + if(myLoveKeyBoardView.getViewType() == 0){ + changeView(1); + }else { + changeView(0); + } + break; + default: + char charCode = (char) primaryCode; + String s = String.valueOf(charCode); + + getCurrentInputConnection().commitText(String.valueOf(charCode), 1); + + int shiftStatus2 = myLoveKeyBoardView.getShift_status(); + KeyBoard keyboard1 = myLoveKeyBoardView.getKeyboard(); + if(shiftStatus2 == 1){ + myLoveKeyBoardView.setShift_status(0); + switchViewData(false,keyboard1); + myLoveKeyBoardView.setKeyboard(keyboard1); + } + + break; + } + + } + + private void changeView(int i) { + myLoveKeyBoardView.setViewType(i); + myLoveKeyBoardView.setKeyboard(new KeyBoard(this, ViewType[i])); + } + + @Override + public void onText(CharSequence text) { + + } + + @Override + public void swipeLeft() { + + } + + @Override + public void swipeRight() { + + } + + @Override + public void swipeDown() { + + } + + @Override + public void swipeUp() { + + } + + private void switchViewData(Boolean success, KeyBoard keyboard) { + List keys = keyboard.getKeys(); + for(int h = 0;h list; + private TextView add_fav; + private LinearLayout fav_lin; + private TextView fav_text_add; + + @SuppressLint("MissingInflatedId") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_favourite); + fav_main = findViewById(R.id.fav_main); + fav_lin =findViewById(R.id.fav_lin); + fav_back = findViewById(R.id.fav_back); + fav_recycle = findViewById(R.id.fav_recycle); + fav_back.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + add_fav = findViewById(R.id.fav_text_add); + add_fav.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(FavouriteActivity.this,ListAllDataActivity.class); + startActivity(intent); + } + }); + fav_lin.setVisibility(View.GONE); + initbackground(); + goGetRecycle(); + } + private void initbackground() { + Window window = getWindow(); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + fav_main.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + } + private void goGetRecycle() { + MyTools.RunIO(new Runnable() { + @Override + public void run() { + list = LikeDataBase.getLikeDataBase().getlikeDataDAO().GetAllData(); + runOnUiThread(new Runnable() { + @Override + public void run() { + if ((list.isEmpty())) { + fav_lin.setVisibility(View.VISIBLE); + } + FavouriteAdapter favouriteAdapter = new FavouriteAdapter( list,FavouriteActivity.this); + // Log.d("----------adapter","_____apapet"+favouriteAdapter); + fav_recycle.setAdapter(favouriteAdapter); + GridLayoutManager gridLayoutManager = new GridLayoutManager(FavouriteActivity.this,2); + fav_recycle.setLayoutManager(gridLayoutManager); + } + }); + + } + }); + + } + @Override + protected void onResume() { + super.onResume(); + fav_lin.setVisibility(View.GONE); + goGetRecycle(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/IntoActivity.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/IntoActivity.java new file mode 100644 index 0000000..69cf87a --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/IntoActivity.java @@ -0,0 +1,43 @@ +package com.kb.myapplication.keyboard.choose.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.view.View; +import android.widget.ProgressBar; + +import androidx.appcompat.app.AppCompatActivity; + +import com.kb.myapplication.keyboard.choose.R; + +public class IntoActivity extends AppCompatActivity { + + private CountDownTimer countDownTimer; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_into); + countDownTimer = new CountDownTimer(1000,200) { + @Override + public void onTick(long millisUntilFinished) { + } + + @Override + public void onFinish() { + Intent intent =new Intent(IntoActivity.this, MainActivity.class); + startActivity(intent); + } + }; + timego(); + } + + private void timego() { + countDownTimer.start(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + countDownTimer.cancel(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/ListAllDataActivity.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/ListAllDataActivity.java new file mode 100644 index 0000000..4204439 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/ListAllDataActivity.java @@ -0,0 +1,51 @@ +package com.kb.myapplication.keyboard.choose.activity; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.LinearLayout; + +import androidx.activity.EdgeToEdge; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.kb.myapplication.keyboard.choose.LoveKeyBoard; +import com.kb.myapplication.keyboard.choose.R; +import com.kb.myapplication.keyboard.choose.adapter.KeyBoardDataAdapter; +import com.kb.myapplication.keyboard.choose.base.MySpace; + +public class ListAllDataActivity extends AppCompatActivity { + + private LinearLayout list_lin; + private RecyclerView main_recycle; + @SuppressLint("MissingInflatedId") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_list_all_data); + main_recycle = findViewById(R.id.main_recycle); + list_lin = findViewById(R.id.list_lin); + initbackground(); + getRecycle(); + } + private void initbackground() { + Window window = getWindow(); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + list_lin.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + } + private void getRecycle() { + MySpace space = new MySpace(10,10,15); + GridLayoutManager gridLayoutManager = new GridLayoutManager(this,2); + main_recycle.setLayoutManager(gridLayoutManager); + main_recycle.addItemDecoration(space); + KeyBoardDataAdapter keyBoardDataAdapter = new KeyBoardDataAdapter(this, LoveKeyBoard.loveDataList); + main_recycle.setAdapter(keyBoardDataAdapter); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/MainActivity.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/MainActivity.java new file mode 100644 index 0000000..7399efb --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/MainActivity.java @@ -0,0 +1,154 @@ +package com.kb.myapplication.keyboard.choose.activity; + +import android.annotation.SuppressLint; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.Uri; +import android.os.Bundle; +import android.view.Gravity; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.PopupMenu; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.view.menu.MenuPopupHelper; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.viewpager.widget.ViewPager; + +import com.kb.myapplication.keyboard.choose.LoveKeyBoard; +import com.kb.myapplication.keyboard.choose.MyTools; +import com.kb.myapplication.keyboard.choose.R; +import com.kb.myapplication.keyboard.choose.adapter.KeyBoardDataAdapter; +import com.kb.myapplication.keyboard.choose.base.MySpace; +import com.kb.myapplication.keyboard.choose.base.ServiceDialog; + +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class MainActivity extends AppCompatActivity { + + private ServiceDialog dialog; + private ImageView main_menu; + private RecyclerView main_recycle; + private LinearLayout menu_like; + private LinearLayout menu_set; + private LinearLayout menu_share; + private LinearLayout menu_pra; + private DrawerLayout main_lin; + private ViewPager viewPager; + private BroadcastReceiver broadcastReceiver; + + @SuppressLint("MissingInflatedId") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + main_lin = findViewById(R.id.main_lin); + main_menu = findViewById(R.id.main_menu); + main_recycle = findViewById(R.id.main_recycle); + menu_like = findViewById(R.id.menu_like); + menu_set = findViewById(R.id.menu_set); + menu_share = findViewById(R.id.menu_share); + menu_pra = findViewById(R.id.menu_pri); + onMyclick(); + broadcastReceiver = new inputReceive(); + registerReceiver(broadcastReceiver, new IntentFilter(Intent.ACTION_INPUT_METHOD_CHANGED)); + main_menu.setOnClickListener(new View.OnClickListener() { + @SuppressLint("RestrictedApi") + @Override + public void onClick(View v) { + main_lin.openDrawer(Gravity.RIGHT); + } + }); + initbackground(); + getRecycle(); + } + + class inputReceive extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + if (dialog != null) { + dialog.refreshBtnStatus(); + } + } + } + + private void gotopricy() { + String url = getString(R.string.privacy); + Intent intent2 = new Intent(Intent.ACTION_VIEW); + intent2.setData(Uri.parse(url)); + startActivity(intent2); + } + + public void shareAPP() { + Intent sharedIntent = new Intent(); + sharedIntent.setAction(Intent.ACTION_SEND); + sharedIntent.setType("text/*"); + sharedIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_app)); //设置要分享的内容 + startActivity(Intent.createChooser(sharedIntent, "Share")); + } + + private void initbackground() { + Window window = getWindow(); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + main_lin.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + } + + private void getRecycle() { + MySpace space = new MySpace(10, 10, 15); + GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2); + main_recycle.setLayoutManager(gridLayoutManager); + main_recycle.addItemDecoration(space); + KeyBoardDataAdapter keyBoardDataAdapter = new KeyBoardDataAdapter(this, LoveKeyBoard.loveDataList); + main_recycle.setAdapter(keyBoardDataAdapter); + } + + private void getDialogsuccess() { + if (dialog == null) { + dialog = new ServiceDialog(MainActivity.this); + } + dialog.show(getSupportFragmentManager(), ""); + } + + public void onMyclick() { + menu_like.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(MainActivity.this, FavouriteActivity.class); + startActivity(intent); + } + }); + menu_set.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getDialogsuccess(); + } + }); + menu_share.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + shareAPP(); + } + }); + menu_pra.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //gotopricy(); + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/PreViewActivity.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/PreViewActivity.java new file mode 100644 index 0000000..88f03f0 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/PreViewActivity.java @@ -0,0 +1,270 @@ +package com.kb.myapplication.keyboard.choose.activity; + +import android.annotation.SuppressLint; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.activity.EdgeToEdge; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.kb.myapplication.keyboard.choose.MyTools; +import com.kb.myapplication.keyboard.choose.R; +import com.kb.myapplication.keyboard.choose.base.ServiceDialog; +import com.kb.myapplication.keyboard.choose.data.KeyBoardData; +import com.kb.myapplication.keyboard.choose.listener.DownloadZipListener; +import com.kb.myapplication.keyboard.choose.listener.Downloadfilezip; +import com.kb.myapplication.keyboard.choose.room.LikeDataBase; +import com.kb.myapplication.keyboard.choose.room.LikeDataEntity; +import com.kb.myapplication.keyboard.choose.value.MyValues; + +import java.io.File; +import java.lang.reflect.Method; +import java.util.List; + +public class PreViewActivity extends AppCompatActivity { + private ImageView pre_back; + private ServiceDialog dialog; + private TextView pre_name; + private String name; + private String url; + private List LIST; + private String unzipPath; + private TextView pre_text_apply; + private ImageView pre_image; + private ImageView pre_fav_image; + private String board_image; + private String thumb; + private ProgressBar pre_pro; + private RelativeLayout pre_main; + private LikeDataEntity entity; + private boolean favsucces = false; + private BroadcastReceiver broadcastReceiver; + @SuppressLint("MissingInflatedId") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_pre_view); + goFindview(); + broadcastReceiver = new inputReceive(); + registerReceiver(broadcastReceiver, new IntentFilter(Intent.ACTION_INPUT_METHOD_CHANGED)); + initbackground(); + goGetData(); + + } + class inputReceive extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + dialog.refreshBtnStatus(); + } + } + + + private void initbackground() { + Window window = getWindow(); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + pre_main.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + } + + private void goGetData() { + Intent intent = getIntent(); + pre_name.setText(intent.getStringExtra(MyValues.KeyBoard_name)); + board_image = intent.getStringExtra(MyValues.KeyBoard_pre); + url = intent.getStringExtra(MyValues.KeyBoard_url); + name = intent.getStringExtra(MyValues.KeyBoard_name); + thumb = intent.getStringExtra(MyValues.KeyBoard_thumb); + Glide.with(this) + .load(board_image) + .error(R.mipmap.ic_launcher) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target target, boolean isFirstResource) { + Log.d("-----failed","-----fail"+null); + pre_pro.setVisibility(View.GONE); + return false; + } + + @Override + public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target target, @NonNull DataSource dataSource, boolean isFirstResource) { + Log.d("-----success","-----fail"+resource); + pre_pro.setVisibility(View.GONE); + return false; + } + }).into(pre_image); + MyTools.RunIO(new Runnable() { + @Override + public void run() { + LIST = LikeDataBase.getLikeDataBase().getlikeDataDAO().QueryTitle(name); + runOnUiThread(new Runnable() { + @Override + public void run() { + if (LIST.isEmpty()) { + pre_fav_image.setBackgroundResource(R.drawable.like_image1); + favsucces = false; + } else { + pre_fav_image.setBackgroundResource(R.drawable.like_image2); + favsucces = true; + } + } + }); + } + }); + File cacheDir = this.getCacheDir(); + unzipPath = cacheDir + "/" + name; + Log.d("------name","---------name"+name); + + } + private void goFindview() { + pre_main = findViewById(R.id.pre_main); + pre_back = findViewById(R.id.pre_back); + pre_name = findViewById(R.id.pre_name); + pre_name.setTypeface(Typeface.createFromAsset(getAssets(),"myfront.ttf")); + pre_text_apply = findViewById(R.id.pre_text_apply); + pre_text_apply.setTypeface(Typeface.createFromAsset(getAssets(),"myfront.ttf")); + pre_image = findViewById(R.id.pre_image); + pre_fav_image = findViewById(R.id.pre_like_image); + pre_pro = findViewById(R.id.pre_pro); + pre_pro.setVisibility(View.VISIBLE); + onMyClick(); + } + + public void onMyClick() { + pre_back.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + pre_text_apply.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!MyTools.FirstSetting() || !MyTools.SecondSetting()) { + getDialogsuccess(); + return; + } + Toast.makeText(PreViewActivity.this, getString(R.string.wait), Toast.LENGTH_SHORT).show(); + goApply(); + } + }); + pre_fav_image.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!favsucces) { + pre_fav_image.setBackgroundResource(R.drawable.like_image2); + favsucces = true; + //pre_fav_image.setBackgroundResource(R.drawable.like_image2); + LikeDataEntity likeDataEntity = new LikeDataEntity(); + likeDataEntity.setTitle(name); + likeDataEntity.setThumb(thumb); + likeDataEntity.setPreview(board_image); + likeDataEntity.setZipUrl(url); + MyTools.RunIO(new Runnable() { + @Override + public void run() { + LikeDataBase.getLikeDataBase().getlikeDataDAO().InsertLikeEntity(likeDataEntity); + } + }); + Toast.makeText(PreViewActivity.this,getString(R.string.fav_success),Toast.LENGTH_SHORT).show(); + } else { + pre_fav_image.setBackgroundResource(R.drawable.like_image1); + favsucces = false; + MyTools.RunIO(new Runnable() { + @Override + public void run() { + LikeDataBase.getLikeDataBase().getlikeDataDAO().DeleteData(name); + } + }); + } + } + + }); + + } + + @Override + protected void onResume() { + super.onResume(); + } + + private void goApply() { + String skinPathByName = MyTools.getBoardSkinPathByName(name); + Log.d("----skinPathByName","------skinPathByName"+skinPathByName); + if (!skinPathByName.isEmpty()) { + setCurrentKeyboardSkin(skinPathByName); + Toast.makeText(PreViewActivity.this, getString(R.string.set_successful), Toast.LENGTH_SHORT).show(); + finish(); + return; + } + MyTools.DownLoadResourceZip(url, this, new DownloadZipListener() { + @Override + public void downloadziplistener(boolean ok, File file) { + if (ok) { + MyTools.OnLoadFileZip(unzipPath, file, new Downloadfilezip() { + @Override + public void downloadfilezip(boolean ok, String filepath) { + if (ok) { + MyTools.saveBoardSkinByName(name, filepath); + setCurrentKeyboardSkin(filepath); + Toast.makeText(PreViewActivity.this, getString(R.string.set_successful), Toast.LENGTH_SHORT).show(); + finish(); + } + } + }); + } else { + } + } + }); + } + private void setCurrentKeyboardSkin(String filepath) { + MyTools.saveKeyboardSkin(filepath); + } + private void getDialogsuccess() { + boolean isSelect = MyTools.FirstSetting(); + boolean isEnable = MyTools.SecondSetting(); + Log.d("----eable","eable"+isEnable); + if (isSelect && isEnable) { + //goApply(); + } else { + if (dialog == null) { + dialog = new ServiceDialog(PreViewActivity.this); + } + dialog.show(getSupportFragmentManager(), ""); + } + } + + @Override + protected void onPause() { + super.onPause(); + + // finish(); + } +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/SettingActivity.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/SettingActivity.java new file mode 100644 index 0000000..801456b --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/activity/SettingActivity.java @@ -0,0 +1,20 @@ +package com.kb.myapplication.keyboard.choose.activity; + +import android.os.Bundle; + +import androidx.activity.EdgeToEdge; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; + +import com.kb.myapplication.keyboard.choose.R; + +public class SettingActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_setting); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/adapter/FavouriteAdapter.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/adapter/FavouriteAdapter.java new file mode 100644 index 0000000..7f437ec --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/adapter/FavouriteAdapter.java @@ -0,0 +1,106 @@ +package com.kb.myapplication.keyboard.choose.adapter; + +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.kb.myapplication.keyboard.choose.R; +import com.kb.myapplication.keyboard.choose.activity.PreViewActivity; +import com.kb.myapplication.keyboard.choose.room.LikeDataEntity; +import com.kb.myapplication.keyboard.choose.value.MyValues; + +import java.io.Serializable; +import java.util.List; + +public class FavouriteAdapter extends RecyclerView.Adapter { + private List likeDataEntities ; + private Context mycontext; + public FavouriteAdapter(List list,Context context){ + likeDataEntities = list; + mycontext = context; + + } + @NonNull + @Override + public FavouriteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(mycontext).inflate(R.layout.fav_recycle,parent,false); + return new FavouriteViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull FavouriteViewHolder holder, int position) { + LikeDataEntity likeDataEntity = likeDataEntities.get(position); + holder.getFav_name().setText(likeDataEntity.getTitle()); + String image = likeDataEntity.getThumb(); + Glide.with(mycontext) + .load(image) + .transform(new RoundedCorners(40)) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target target, boolean isFirstResource) { + return false; + } + + @Override + public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target target, @NonNull DataSource dataSource, boolean isFirstResource) { + return false; + } + }).into(holder.getFav_image()); + holder.getFav_recycle_lay().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(mycontext, PreViewActivity.class); + intent.putExtra(MyValues.KeyBoard_name,likeDataEntity.getTitle()); + intent.putExtra(MyValues.KeyBoard_pre,likeDataEntity.getPreview()); + intent.putExtra(MyValues.KeyBoard_url,likeDataEntity.getZipUrl()); + intent.putExtra(MyValues.KeyBoard_thumb,likeDataEntity.getThumb()); + mycontext.startActivity(intent); + } + }); + } + + @Override + public int getItemCount() { + return likeDataEntities.size(); + } + + public class FavouriteViewHolder extends RecyclerView.ViewHolder { + private ImageView fav_image; + private TextView fav_name; + private RelativeLayout fav_recycle_lay; + public FavouriteViewHolder(@NonNull View itemView) { + super(itemView); + fav_image = itemView.findViewById(R.id.fav_image); + fav_name = itemView.findViewById(R.id.fav_name); + fav_recycle_lay = itemView.findViewById(R.id.fav_relative_lay); + } + + public ImageView getFav_image() { + return fav_image; + } + + public TextView getFav_name() { + return fav_name; + } + + public RelativeLayout getFav_recycle_lay() { + return fav_recycle_lay; + } + } +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/adapter/KeyBoardDataAdapter.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/adapter/KeyBoardDataAdapter.java new file mode 100644 index 0000000..b231bb9 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/adapter/KeyBoardDataAdapter.java @@ -0,0 +1,126 @@ +package com.kb.myapplication.keyboard.choose.adapter; + +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.kb.myapplication.keyboard.choose.MyTools; +import com.kb.myapplication.keyboard.choose.R; +import com.kb.myapplication.keyboard.choose.activity.PreViewActivity; +import com.kb.myapplication.keyboard.choose.data.KeyBoardData; +import com.kb.myapplication.keyboard.choose.room.LikeDataBase; +import com.kb.myapplication.keyboard.choose.room.LikeDataEntity; +import com.kb.myapplication.keyboard.choose.value.MyValues; + +import java.util.List; + +public class KeyBoardDataAdapter extends RecyclerView.Adapter { + private List keyBoardData; + private Context mycon; + private LikeDataEntity entity; + public KeyBoardDataAdapter(Context context, List data){ + mycon = context; + keyBoardData = data; + } + @NonNull + @Override + public DataViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(mycon).inflate(R.layout.keyboard_thumb, parent, false); + DataViewHolder dataViewHolder = new DataViewHolder(itemView); + return dataViewHolder; + } + + @Override + public void onBindViewHolder(@NonNull DataViewHolder holder, int position) { + KeyBoardData keyBoardData1 = keyBoardData.get(position); + Log.d("-----keyBoardData1.getThumb()","----keyBoardData1.getThumb()"+keyBoardData1.getThumb()); + Glide.with(mycon) + .load(keyBoardData1.getThumb()) + .transform(new RoundedCorners(30)) + .error(R.mipmap.ic_launcher) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target target, boolean isFirstResource) { + return false; + } + + @Override + public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target target, @NonNull DataSource dataSource, boolean isFirstResource) { + return false; + } + }).into(holder.getThumb_image()); + holder.getThumb_name().setText(keyBoardData1.getTitle()); + holder.getThumb_fra().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(mycon, PreViewActivity.class); + intent.putExtra(MyValues.KeyBoard_name,keyBoardData1.getTitle()); + intent.putExtra(MyValues.KeyBoard_pre,keyBoardData1.getPreview()); + intent.putExtra(MyValues.KeyBoard_url,keyBoardData1.getZipUrl()); + intent.putExtra(MyValues.KeyBoard_thumb,keyBoardData1.getThumb()); + mycon.startActivity(intent); + } + }); + } + + @Override + public int getItemCount() { + return keyBoardData.size(); + } + + public static final class DataViewHolder extends RecyclerView.ViewHolder { + private TextView thumb_name; + private ImageView thumb_image; + private RelativeLayout thumb_fra; + + public DataViewHolder(@NonNull View itemView) { + super(itemView); + thumb_image = itemView.findViewById(R.id.thumb_image); + thumb_name = itemView.findViewById(R.id.thumb_name); + thumb_fra = itemView.findViewById(R.id.thumb_fra); + } + + public TextView getThumb_name() { + return thumb_name; + } + + public void setThumb_name(TextView thumb_name) { + this.thumb_name = thumb_name; + } + + public ImageView getThumb_image() { + return thumb_image; + } + + public void setThumb_image(ImageView thumb_image) { + this.thumb_image = thumb_image; + } + + public RelativeLayout getThumb_fra() { + return thumb_fra; + } + + public void setThumb_fra(RelativeLayout thumb_fra) { + this.thumb_fra = thumb_fra; + } + } +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/base/CustomViewConfig.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/CustomViewConfig.java new file mode 100644 index 0000000..e123a27 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/CustomViewConfig.java @@ -0,0 +1,236 @@ +package com.kb.myapplication.keyboard.choose.base; + + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.StateListDrawable; +import android.util.Xml; + +import androidx.core.content.ContextCompat; + +import com.kb.myapplication.keyboard.choose.value.MyValues; +import com.kb.myapplication.keyboard.choose.MyTools; +import com.kb.myapplication.keyboard.choose.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.util.Objects; + +public class CustomViewConfig { + private String Bg_action_normal = "btn_keyboard_key_functional_normal.9.png"; + private String jpg_BG = "keyboard_background.jpg"; + private String color_normal_key = "key_text_color_normal"; + private String color_action_key = "key_text_color_functional"; + private String Bg_pressed = "btn_keyboard_key_normal_pressed.9.png"; + private String Bg_normal = "btn_keyboard_key_normal_normal.9.png"; + private String path_drawxh = "/drawable-xhdpi-v4/"; + private String path_drawxxh = "/drawable-xxhdpi-v4/"; + private String path_color = "/colors.xml"; + private String icon_del = "sym_keyboard_delete_normal.png"; + private String icon_shift = "sym_keyboard_shift.png"; + private String Bg_action_pressed = "btn_keyboard_key_functional_pressed.9.png"; + private String icon_shift_lock = "sym_keyboard_shift_locked.png"; + + private String Bg_space_normal = "btn_keyboard_spacekey_normal_normal.9.png"; + private String Bg_space_pressed = "btn_keyboard_spacekey_normal_pressed.9.png"; + + + private Drawable BgActionDraw; + private Drawable BgSpaceDraw; + private Drawable BgNormalDraw; + + private Drawable iconShift = ContextCompat.getDrawable(MyValues.app, R.drawable.ico_shift_lit); + private Drawable iconDel = ContextCompat.getDrawable(MyValues.app, R.drawable.del_icon); + private Drawable BG = ContextCompat.getDrawable(MyValues.app, R.drawable.de_keyboard_bg); + + private int keyNoramlcolor = MyValues.app.getResources().getColor(R.color.white, null); + + private int keyActioncolor = MyValues.app.getResources().getColor(R.color.white, null); + + private Drawable iconShiftLock = ContextCompat.getDrawable(MyValues.app, R.drawable.ico_shift_lit); + + + public Drawable getBG() { + return BG; + } + + public Drawable getBgActionDraw() { + return BgActionDraw; + } + + public Drawable getBgNormalDraw() { + return BgNormalDraw; + } + + public Drawable getBgSpaceDraw() { + return BgSpaceDraw; + } + + public Drawable getIconDel() { + return iconDel; + } + + public Drawable getIconShift() { + return iconShift; + } + + public Drawable getIconShiftLock() { + return iconShiftLock; + } + + public int getKeyNoramlcolor() { + return keyNoramlcolor; + } + + + public int getKeyActioncolor() { + return keyActioncolor; + } + + public void init() { + + iconShift = ContextCompat.getDrawable(MyValues.app, R.drawable.ico_shift_lit); + iconDel = ContextCompat.getDrawable(MyValues.app, R.drawable.del_icon); + BG = ContextCompat.getDrawable(MyValues.app, R.drawable.de_keyboard_bg); + + keyNoramlcolor = MyValues.app.getResources().getColor(R.color.white, null); + + iconShiftLock = ContextCompat.getDrawable(MyValues.app, R.drawable.ico_shift_lit); + + + Drawable drawable1 = ContextCompat.getDrawable( + MyValues.app, + R.drawable.de_keybg_press + ); + Drawable drawable = ContextCompat.getDrawable(MyValues.app, R.drawable.de_keybg); + StateListDrawable status = MyTools.getStatus(drawable, drawable1); + BgActionDraw = status; + BgNormalDraw = status; + BgSpaceDraw = status; + } + + private Drawable getKeyBackGround(Context context, String resDirPath, String drawName) { + ///data/user/0/com.keyboardskinning.theme/cache/Funny Xmas Stitch/new-android-funny_xmas_stitch-theme-aws_master_zip_theme-version-2_noad_336433_972836_223993/res/drawable-xxhdpi-v4/btn_keyboard_key_normal_normal.9.png + String filePath = resDirPath + path_drawxh + drawName; + File file = new File(filePath); + if (!file.exists()) { + return null; + } + // 获取位图尺寸 + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(filePath, options); + + // 计算缩放比例 + options.inSampleSize = calculateInSampleSize(options, 100, 100); // 根据需要调整目标宽高 + options.inJustDecodeBounds = false; + + + + Bitmap bitmap = BitmapFactory.decodeFile(filePath, options); + + return new BitmapDrawable(context.getResources(), bitmap); + } + + public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { + // 原始宽高 + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + // 计算最合适的 inSampleSize 值 + while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { + inSampleSize *= 2; + } + } + return inSampleSize; + } + + + private Drawable getBackGround(Context context, String resDirPath) { + String filePath = resDirPath + path_drawxxh + jpg_BG; + if (!new File(filePath).exists()) { + return null; + } + Bitmap bitmap = BitmapFactory.decodeFile(filePath); + BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), bitmap); + return bitmapDrawable; + } + + private void updateKeyColor(String resDirPath) { + + String colorXmlPath = resDirPath + path_color; + File file = new File(colorXmlPath); + if (!file.exists()) { + return; + } + try { + XmlPullParser xmlPullParser = Xml.newPullParser(); + + String s = MyTools.parseString(file); + xmlPullParser.setInput(new StringReader(s)); + xmlPullParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); + int eventT = xmlPullParser.getEventType(); + while (eventT != XmlPullParser.END_DOCUMENT) { + if (eventT == XmlPullParser.START_TAG && (Objects.equals(xmlPullParser.getName(), "color") || Objects.equals(xmlPullParser.getName(), "item"))) { + String value = xmlPullParser.getAttributeValue(null, "name"); + if (value != null && value.equals(color_normal_key)) { + keyNoramlcolor = Color.parseColor(xmlPullParser.nextText()); + + } + if (value != null && value.equals(color_action_key)) { + keyActioncolor = Color.parseColor(xmlPullParser.nextText()); + + } + } + eventT = xmlPullParser.next(); + } + } catch (XmlPullParserException exception) { + + } catch (IOException e) { + throw new RuntimeException(e); + } + + + } + + public void updateConfig(Context con) { + String resDirPath = MyTools.getKeyboardSkin(); + + if (!resDirPath.isEmpty()) { + updateKeyColor(resDirPath); + BG = getBackGround(con, resDirPath); + + Drawable keyBackGround = getKeyBackGround(con, resDirPath, Bg_normal); + Drawable keyBackGround1 = getKeyBackGround(con, resDirPath, Bg_pressed); + BgNormalDraw = MyTools.getStatus(keyBackGround, keyBackGround1); + + Drawable keyBackGround2 = getKeyBackGround(con, resDirPath, Bg_action_normal); + Drawable keyBackGround3 = getKeyBackGround(con, resDirPath, Bg_action_pressed); + BgActionDraw = MyTools.getStatus(keyBackGround2, keyBackGround3); + + Drawable keyBackGround4 = getKeyBackGround(con, resDirPath, Bg_space_normal); + Drawable keyBackGround5 = getKeyBackGround(con, resDirPath, Bg_space_pressed); + BgSpaceDraw = MyTools.getStatus(keyBackGround4, keyBackGround5); + + iconDel = getKeyBackGround(con, resDirPath, icon_del); + iconShift = getKeyBackGround(con, resDirPath, icon_shift); + iconShiftLock = getKeyBackGround(con, resDirPath, icon_shift_lock); + } + + } + + +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/base/DrawIcon.kt b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/DrawIcon.kt new file mode 100644 index 0000000..17b12a4 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/DrawIcon.kt @@ -0,0 +1,53 @@ +package com.kb.myapplication.keyboard.choose.base + +import android.graphics.Canvas +import android.graphics.Rect +import android.graphics.drawable.Drawable + + +object DrawIcon { + + public fun onDrawKeyIcon(currentKey: KeyBoard.Key, + drawKeyIcon: Drawable, + myCanvas: Canvas, + myKeyBoardView:MyLoveKeyBoardView + ){ + drawKeyIcon.apply { + currentKey.icon = this + + var icon_w = currentKey.icon.intrinsicWidth.toFloat() + var icon_wr = icon_w / currentKey.width.toFloat() + var icon_h = currentKey.icon.intrinsicHeight.toFloat() + var icon_hr = icon_h / currentKey.height.toFloat() + + + var tep1 = 0f + var tep2 = 0f + if (icon_wr > icon_hr) { + tep2 = icon_wr + tep1 = icon_wr.coerceAtLeast(0.5f) + + } else { + tep2 = icon_hr + tep1 = icon_hr.coerceAtLeast(0.5f) + + } + icon_h = (icon_h / tep2) * tep1 + icon_w = (icon_w / tep2) * tep1 + currentKey.icon.let { + it.bounds = Rect().apply { + + top = + (currentKey.y + myKeyBoardView.paddingTop + (currentKey.height - icon_h) / 2f).toInt() + left = + (currentKey.x + myKeyBoardView.paddingLeft + (currentKey.width - icon_w) / 2f).toInt() + bottom = (top + icon_h).toInt() + right = (left + icon_w).toInt() + + } + it.draw(myCanvas) + } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/base/KeyBoard.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/KeyBoard.java new file mode 100644 index 0000000..f0afb10 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/KeyBoard.java @@ -0,0 +1,848 @@ +package com.kb.myapplication.keyboard.choose.base; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; +import android.util.Xml; + +import androidx.annotation.XmlRes; + +import com.kb.myapplication.keyboard.choose.R; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +public class KeyBoard { + + static final String TAG = "Keyboard"; + + // Keyboard XML Tags + private static final String TAG_KEYBOARD = "Keyboard"; + private static final String TAG_ROW = "Row"; + private static final String TAG_KEY = "Key"; + + public static final int EDGE_LEFT = 0x01; + public static final int EDGE_RIGHT = 0x02; + public static final int EDGE_TOP = 0x04; + public static final int EDGE_BOTTOM = 0x08; + + public static final int KEYCODE_SHIFT = -1; + public static final int KEYCODE_MODE_CHANGE = -2; + public static final int KEYCODE_CANCEL = -3; + public static final int KEYCODE_DONE = -4; + public static final int KEYCODE_DELETE = -5; + public static final int KEYCODE_ALT = -6; + public static final int KEYCODE_BLANK = 32; + public static final int KEYCODE_SHIFT_123 = -360; + public static final int KEYCODE_SHIFT_SYMBOL = -361; + + /** Keyboard label **/ + private CharSequence mLabel; + + /** Horizontal gap default for all rows */ + private int mDefaultHorizontalGap; + + /** Default key width */ + private int mDefaultWidth; + + /** Default key height */ + private int mDefaultHeight; + + /** Default gap between rows */ + private int mDefaultVerticalGap; + + /** Is the keyboard in the shifted state */ + private boolean mShifted; + + /** Key instance for the shift key, if present */ + private Key[] mShiftKeys = { null, null }; + + /** Key index for the shift key, if present */ + private int[] mShiftKeyIndices = {-1, -1}; + + /** Current key width, while loading the keyboard */ + private int mKeyWidth; + + /** Current key height, while loading the keyboard */ + private int mKeyHeight; + + /** Total height of the keyboard, including the padding and keys */ + private int mTotalHeight; + + /** + * Total width of the keyboard, including left side gaps and keys, but not any gaps on the + * right side. + */ + private int mTotalWidth; + + /** List of keys in this keyboard */ + private List mKeys; + + /** List of modifier keys such as Shift & Alt, if any */ + private List mModifierKeys; + + /** Width of the screen available to fit the keyboard */ + private int mDisplayWidth; + + /** Height of the screen */ + private int mDisplayHeight; + + /** Keyboard mode, or zero, if none. */ + private int mKeyboardMode; + + // Variables for pre-computing nearest keys. + + private static final int GRID_WIDTH = 10; + private static final int GRID_HEIGHT = 5; + private static final int GRID_SIZE = GRID_WIDTH * GRID_HEIGHT; + private int mCellWidth; + private int mCellHeight; + private int[][] mGridNeighbors; + private int mProximityThreshold; + /** Number of key widths from current touch point to search for nearest keys. */ + private static float SEARCH_DISTANCE = 1.8f; + + private ArrayList rows = new ArrayList<>(); + + + public static class Row { + /** Default width of a key in this row. */ + public int defaultWidth; + /** Default height of a key in this row. */ + public int defaultHeight; + /** Default horizontal gap between keys in this row. */ + public int defaultHorizontalGap; + /** Vertical gap following this row. */ + public int verticalGap; + + ArrayList mKeys = new ArrayList<>(); + + + public int rowEdgeFlags; + + /** The keyboard mode for this row */ + public int mode; + + private KeyBoard parent; + + public Row(KeyBoard parent) { + this.parent = parent; + } + + public Row(Resources res, KeyBoard parent, XmlResourceParser parser) { + this.parent = parent; + TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.style_view); + defaultWidth = getDimensionOrFraction(a, + R.styleable.style_view_android_keyWidth, + parent.mDisplayWidth, parent.mDefaultWidth); + defaultHeight = getDimensionOrFraction(a, + R.styleable.style_view_android_keyHeight, + parent.mDisplayHeight, parent.mDefaultHeight); + defaultHorizontalGap = getDimensionOrFraction(a, + R.styleable.style_view_android_horizontalGap, + parent.mDisplayWidth, parent.mDefaultHorizontalGap); + verticalGap = getDimensionOrFraction(a, + R.styleable.style_view_android_verticalGap, + parent.mDisplayHeight, parent.mDefaultVerticalGap); + a.recycle(); + a = res.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.style_row); + rowEdgeFlags = a.getInt(R.styleable.style_row_android_rowEdgeFlags, 0); + mode = a.getResourceId(R.styleable.style_row_android_keyboardMode, + 0); + } + } + + /** + * Class for describing the position and characteristics of a single key in the keyboard. + * + * @attr ref android.R.styleable#King_Keyboard_keyWidth + * @attr ref android.R.styleable#King_Keyboard_keyHeight + * @attr ref android.R.styleable#King_Keyboard_horizontalGap + * @attr ref android.R.styleable#King_Keyboard_Key_codes + * @attr ref android.R.styleable#King_Keyboard_Key_keyIcon + * @attr ref android.R.styleable#King_Keyboard_Key_keyLabel + * @attr ref android.R.styleable#King_Keyboard_Key_iconPreview + * @attr ref android.R.styleable#King_Keyboard_Key_isSticky + * @attr ref android.R.styleable#King_Keyboard_Key_isRepeatable + * @attr ref android.R.styleable#King_Keyboard_Key_isModifier + * @attr ref android.R.styleable#King_Keyboard_Key_popupKeyboard + * @attr ref android.R.styleable#King_Keyboard_Key_popupCharacters + * @attr ref android.R.styleable#King_Keyboard_Key_keyOutputText + * @attr ref android.R.styleable#King_Keyboard_Key_keyEdgeFlags + */ + public static class Key { + /** + * All the key codes (unicode or custom code) that this key could generate, zero'th + * being the most important. + */ + public int[] codes; + + /** Label to display */ + public CharSequence label; + + /** Icon to display instead of a label. Icon takes precedence over a label */ + public Drawable icon; + /** Preview version of the icon, for the preview popup */ + public Drawable iconPreview; + /** Width of the key, not including the gap */ + public int width; + /** Height of the key, not including the gap */ + public int height; + /** The horizontal gap before this key */ + public int gap; + /** Whether this key is sticky, i.e., a toggle key */ + public boolean sticky; + /** X coordinate of the key in the keyboard layout */ + public int x; + /** Y coordinate of the key in the keyboard layout */ + public int y; + /** The current pressed state of this key */ + public boolean pressed; + /** If this is a sticky key, is it on? */ + public boolean on; + /** Text to output when pressed. This can be multiple characters, like ".com" */ + public CharSequence text; + /** Popup characters */ + public CharSequence popupCharacters; + + /** + * Flags that specify the anchoring to edges of the keyboard for detecting touch events + * that are just out of the boundary of the key. This is a bit mask of + * {@link KeyBoard#EDGE_LEFT}, {@link KeyBoard#EDGE_RIGHT}, {@link KeyBoard#EDGE_TOP} and + * {@link KeyBoard#EDGE_BOTTOM}. + */ + public int edgeFlags; + /** Whether this is a modifier key, such as Shift or Alt */ + public boolean modifier; + /** The keyboard that this key belongs to */ + private KeyBoard keyboard; + /** + * If this key pops up a mini keyboard, this is the resource id for the XML layout for that + * keyboard. + */ + public int popupResId; + /** Whether this key repeats itself when held down */ + public boolean repeatable; + + + private final static int[] KEY_STATE_NORMAL_ON = { + android.R.attr.state_checkable, + android.R.attr.state_checked + }; + + private final static int[] KEY_STATE_PRESSED_ON = { + android.R.attr.state_pressed, + android.R.attr.state_checkable, + android.R.attr.state_checked + }; + + private final static int[] KEY_STATE_NORMAL_OFF = { + android.R.attr.state_checkable + }; + + private final static int[] KEY_STATE_PRESSED_OFF = { + android.R.attr.state_pressed, + android.R.attr.state_checkable + }; + + private final static int[] KEY_STATE_NORMAL = { + }; + + private final static int[] KEY_STATE_PRESSED = { + android.R.attr.state_pressed + }; + + /** Create an empty key with no attributes. */ + public Key(Row parent) { + keyboard = parent.parent; + height = parent.defaultHeight; + width = parent.defaultWidth; + gap = parent.defaultHorizontalGap; + edgeFlags = parent.rowEdgeFlags; + } + + /** Create a key with the given top-left coordinate and extract its attributes from + * the XML parser. + * @param res resources associated with the caller's context + * @param parent the row that this key belongs to. The row must already be attached to + * a {@link KeyBoard}. + * @param x the x coordinate of the top-left + * @param y the y coordinate of the top-left + * @param parser the XML parser containing the attributes for this key + */ + public Key(Resources res, Row parent, int x, int y, XmlResourceParser parser) { + this(parent); + + this.x = x; + this.y = y; + + TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.style_view); + + width = getDimensionOrFraction(a, + R.styleable.style_view_android_keyWidth, + keyboard.mDisplayWidth, parent.defaultWidth); + height = getDimensionOrFraction(a, + R.styleable.style_view_android_keyHeight, + keyboard.mDisplayHeight, parent.defaultHeight); + gap = getDimensionOrFraction(a, + R.styleable.style_view_android_horizontalGap, + keyboard.mDisplayWidth, parent.defaultHorizontalGap); + a.recycle(); + a = res.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.style_key); + this.x += gap; + TypedValue codesValue = new TypedValue(); + a.getValue(R.styleable.style_key_android_codes, + codesValue); + if (codesValue.type == TypedValue.TYPE_INT_DEC + || codesValue.type == TypedValue.TYPE_INT_HEX) { + codes = new int[] { codesValue.data }; + } else if (codesValue.type == TypedValue.TYPE_STRING) { + codes = parseCSV(codesValue.string.toString()); + } + + iconPreview = a.getDrawable(R.styleable.style_key_android_iconPreview); + if (iconPreview != null) { + iconPreview.setBounds(0, 0, iconPreview.getIntrinsicWidth(), + iconPreview.getIntrinsicHeight()); + } + popupCharacters = a.getText( + R.styleable.style_key_android_popupCharacters); + popupResId = a.getResourceId( + R.styleable.style_key_android_popupKeyboard, 0); + repeatable = a.getBoolean( + R.styleable.style_key_android_isRepeatable, false); + modifier = a.getBoolean( + R.styleable.style_key_android_isModifier, false); + sticky = a.getBoolean( + R.styleable.style_key_android_isSticky, false); + edgeFlags = a.getInt(R.styleable.style_key_android_keyEdgeFlags, 0); + edgeFlags |= parent.rowEdgeFlags; + + icon = a.getDrawable( + R.styleable.style_key_android_keyIcon); + if (icon != null) { + icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); + } + label = a.getText(R.styleable.style_key_android_keyLabel); + text = a.getText(R.styleable.style_key_android_keyOutputText); + + if (codes == null && !TextUtils.isEmpty(label)) { + codes = new int[] { label.charAt(0) }; + } + a.recycle(); + } + + /** + * Informs the key that it has been pressed, in case it needs to change its appearance or + * state. + * @see #onReleased(boolean) + */ + public void onPressed() { + pressed = !pressed; + } + + /** + * Changes the pressed state of the key. + * + *

Toggled state of the key will be flipped when all the following conditions are + * fulfilled:

+ * + *
    + *
  • This is a sticky key, that is, {@link #sticky} is {@code true}. + *
  • The parameter {@code inside} is {@code true}. + *
  • {@link android.os.Build.VERSION#SDK_INT} is greater than + * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}. + *
+ * + * @param inside whether the finger was released inside the key. Works only on Android M and + * later. See the method document for details. + * @see #onPressed() + */ + public void onReleased(boolean inside) { + pressed = !pressed; + if (sticky && inside) { + on = !on; + } + } + + int[] parseCSV(String value) { + int count = 0; + int lastIndex = 0; + if (value.length() > 0) { + count++; + while ((lastIndex = value.indexOf(",", lastIndex + 1)) > 0) { + count++; + } + } + int[] values = new int[count]; + count = 0; + StringTokenizer st = new StringTokenizer(value, ","); + while (st.hasMoreTokens()) { + try { + values[count++] = Integer.parseInt(st.nextToken()); + } catch (NumberFormatException nfe) { + Log.e(TAG, "Error parsing keycodes " + value); + } + } + return values; + } + + /** + * Detects if a point falls inside this key. + * @param x the x-coordinate of the point + * @param y the y-coordinate of the point + * @return whether or not the point falls inside the key. If the key is attached to an edge, + * it will assume that all points between the key and the edge are considered to be inside + * the key. + */ + public boolean isInside(int x, int y) { + boolean leftEdge = (edgeFlags & EDGE_LEFT) > 0; + boolean rightEdge = (edgeFlags & EDGE_RIGHT) > 0; + boolean topEdge = (edgeFlags & EDGE_TOP) > 0; + boolean bottomEdge = (edgeFlags & EDGE_BOTTOM) > 0; + if ((x >= this.x || (leftEdge && x <= this.x + this.width)) + && (x < this.x + this.width || (rightEdge && x >= this.x)) + && (y >= this.y || (topEdge && y <= this.y + this.height)) + && (y < this.y + this.height || (bottomEdge && y >= this.y))) { + return true; + } else { + return false; + } + } + + /** + * Returns the square of the distance between the center of the key and the given point. + * @param x the x-coordinate of the point + * @param y the y-coordinate of the point + * @return the square of the distance of the point from the center of the key + */ + public int squaredDistanceFrom(int x, int y) { + int xDist = this.x + width / 2 - x; + int yDist = this.y + height / 2 - y; + return xDist * xDist + yDist * yDist; + } + + /** + * Returns the drawable state for the key, based on the current state and type of the key. + * @return the drawable state of the key. + * @see android.graphics.drawable.StateListDrawable#setState(int[]) + */ + public int[] getCurrentDrawableState() { + int[] states = KEY_STATE_NORMAL; + + if (on) { + if (pressed) { + states = KEY_STATE_PRESSED_ON; + } else { + states = KEY_STATE_NORMAL_ON; + } + } else { + if (sticky) { + if (pressed) { + states = KEY_STATE_PRESSED_OFF; + } else { + states = KEY_STATE_NORMAL_OFF; + } + } else { + if (pressed) { + states = KEY_STATE_PRESSED; + } + } + } + return states; + } + } + + /** + * Creates a keyboard from the given xml key layout file. + * @param context the application or service context + * @param xmlLayoutResId the resource file that contains the keyboard layout and keys. + */ + public KeyBoard(Context context, int xmlLayoutResId) { + this(context, xmlLayoutResId, 0); + } + + /** + * Creates a keyboard from the given xml key layout file. Weeds out rows + * that have a keyboard mode defined but don't match the specified mode. + * @param context the application or service context + * @param xmlLayoutResId the resource file that contains the keyboard layout and keys. + * @param modeId keyboard mode identifier + * @param width sets width of keyboard + * @param height sets height of keyboard + */ + public KeyBoard(Context context, @XmlRes int xmlLayoutResId, int modeId, int width, + int height) { + mDisplayWidth = width; + mDisplayHeight = height; + + mDefaultHorizontalGap = 0; + mDefaultWidth = mDisplayWidth / 10; + mDefaultVerticalGap = 0; + mDefaultHeight = mDefaultWidth; + mKeys = new ArrayList<>(); + mModifierKeys = new ArrayList<>(); + mKeyboardMode = modeId; + loadKeyboard(context, context.getResources().getXml(xmlLayoutResId)); + } + + /** + * Creates a keyboard from the given xml key layout file. Weeds out rows + * that have a keyboard mode defined but don't match the specified mode. + * @param context the application or service context + * @param xmlLayoutResId the resource file that contains the keyboard layout and keys. + * @param modeId keyboard mode identifier + */ + public KeyBoard(Context context, @XmlRes int xmlLayoutResId, int modeId) { + DisplayMetrics dm = context.getResources().getDisplayMetrics(); + mDisplayWidth = dm.widthPixels; + mDisplayHeight = dm.heightPixels; + //Log.v(TAG, "keyboard's display metrics:" + dm); + + mDefaultHorizontalGap = 0; + mDefaultWidth = mDisplayWidth / 10; + mDefaultVerticalGap = 0; + mDefaultHeight = mDefaultWidth; + mKeys = new ArrayList<>(); + mModifierKeys = new ArrayList<>(); + mKeyboardMode = modeId; + loadKeyboard(context, context.getResources().getXml(xmlLayoutResId)); + } + + public KeyBoard(Context context, int layoutTemplateResId, + CharSequence characters, int columns, int horizontalPadding) { + this(context, layoutTemplateResId); + int x = 0; + int y = 0; + int column = 0; + mTotalWidth = 0; + + Row row = new Row(this); + row.defaultHeight = mDefaultHeight; + row.defaultWidth = mDefaultWidth; + row.defaultHorizontalGap = mDefaultHorizontalGap; + row.verticalGap = mDefaultVerticalGap; + row.rowEdgeFlags = EDGE_TOP | EDGE_BOTTOM; + final int maxColumns = columns == -1 ? Integer.MAX_VALUE : columns; + for (int i = 0; i < characters.length(); i++) { + char c = characters.charAt(i); + if (column >= maxColumns + || x + mDefaultWidth + horizontalPadding > mDisplayWidth) { + x = 0; + y += mDefaultVerticalGap + mDefaultHeight; + column = 0; + } + final Key key = new Key(row); + key.x = x; + key.y = y; + key.label = String.valueOf(c); + key.codes = new int[] { c }; + column++; + x += key.width + key.gap; + mKeys.add(key); + row.mKeys.add(key); + if (x > mTotalWidth) { + mTotalWidth = x; + } + } + mTotalHeight = y + mDefaultHeight; + rows.add(row); + } + + final void resize(int newWidth, int newHeight) { + int numRows = rows.size(); + for (int rowIndex = 0; rowIndex < numRows; ++rowIndex) { + Row row = rows.get(rowIndex); + int numKeys = row.mKeys.size(); + int totalGap = 0; + int totalWidth = 0; + for (int keyIndex = 0; keyIndex < numKeys; ++keyIndex) { + Key key = row.mKeys.get(keyIndex); + if (keyIndex > 0) { + totalGap += key.gap; + } + totalWidth += key.width; + } + if (totalGap + totalWidth > newWidth) { + int x = 0; + float scaleFactor = (float)(newWidth - totalGap) / totalWidth; + for (int keyIndex = 0; keyIndex < numKeys; ++keyIndex) { + Key key = row.mKeys.get(keyIndex); + key.width *= scaleFactor; + key.x = x; + x += key.width + key.gap; + } + } + } + mTotalWidth = newWidth; + // TODO: This does not adjust the vertical placement according to the new size. + // The main problem in the previous code was horizontal placement/size, but we should + // also recalculate the vertical sizes/positions when we get this resize call. + } + + public List getKeys() { + return mKeys; + } + + public List getModifierKeys() { + return mModifierKeys; + } + + protected int getHorizontalGap() { + return mDefaultHorizontalGap; + } + + protected void setHorizontalGap(int gap) { + mDefaultHorizontalGap = gap; + } + + protected int getVerticalGap() { + return mDefaultVerticalGap; + } + + protected void setVerticalGap(int gap) { + mDefaultVerticalGap = gap; + } + + protected int getKeyHeight() { + return mDefaultHeight; + } + + protected void setKeyHeight(int height) { + mDefaultHeight = height; + } + + protected int getKeyWidth() { + return mDefaultWidth; + } + + protected void setKeyWidth(int width) { + mDefaultWidth = width; + } + + /** + * Returns the total height of the keyboard + * @return the total height of the keyboard + */ + public int getHeight() { + return mTotalHeight; + } + + public int getMinWidth() { + return mTotalWidth; + } + + public boolean setShifted(boolean shiftState) { + for (Key shiftKey : mShiftKeys) { + if (shiftKey != null) { + shiftKey.on = shiftState; + } + } + if (mShifted != shiftState) { + mShifted = shiftState; + return true; + } + return false; + } + + public boolean isShifted() { + return mShifted; + } + + /** + * @hide + */ + public int[] getShiftKeyIndices() { + return mShiftKeyIndices; + } + + public int getShiftKeyIndex() { + return mShiftKeyIndices[0]; + } + + private void computeNearestNeighbors() { + // Round-up so we don't have any pixels outside the grid + mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH; + mCellHeight = (getHeight() + GRID_HEIGHT - 1) / GRID_HEIGHT; + mGridNeighbors = new int[GRID_SIZE][]; + int[] indices = new int[mKeys.size()]; + final int gridWidth = GRID_WIDTH * mCellWidth; + final int gridHeight = GRID_HEIGHT * mCellHeight; + for (int x = 0; x < gridWidth; x += mCellWidth) { + for (int y = 0; y < gridHeight; y += mCellHeight) { + int count = 0; + for (int i = 0; i < mKeys.size(); i++) { + final Key key = mKeys.get(i); + if (key.squaredDistanceFrom(x, y) < mProximityThreshold || + key.squaredDistanceFrom(x + mCellWidth - 1, y) < mProximityThreshold || + key.squaredDistanceFrom(x + mCellWidth - 1, y + mCellHeight - 1) + < mProximityThreshold || + key.squaredDistanceFrom(x, y + mCellHeight - 1) < mProximityThreshold) { + indices[count++] = i; + } + } + int [] cell = new int[count]; + System.arraycopy(indices, 0, cell, 0, count); + mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell; + } + } + } + + /** + * Returns the indices of the keys that are closest to the given point. + * @param x the x-coordinate of the point + * @param y the y-coordinate of the point + * @return the array of integer indices for the nearest keys to the given point. If the given + * point is out of range, then an array of size zero is returned. + */ + public int[] getNearestKeys(int x, int y) { + if (mGridNeighbors == null) computeNearestNeighbors(); + if (x >= 0 && x < getMinWidth() && y >= 0 && y < getHeight()) { + int index = (y / mCellHeight) * GRID_WIDTH + (x / mCellWidth); + if (index < GRID_SIZE) { + return mGridNeighbors[index]; + } + } + return new int[0]; + } + + protected Row createRowFromXml(Resources res, XmlResourceParser parser) { + return new Row(res, this, parser); + } + + protected Key createKeyFromXml(Resources res, Row parent, int x, int y, + XmlResourceParser parser) { + return new Key(res, parent, x, y, parser); + } + + private void loadKeyboard(Context context, XmlResourceParser parser) { + boolean inKey = false; + boolean inRow = false; + boolean leftMostKey = false; + int row = 0; + int x = 0; + int y = 0; + Key key = null; + Row currentRow = null; + Resources res = context.getResources(); + boolean skipRow = false; + + try { + int event; + while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) { + if (event == XmlResourceParser.START_TAG) { + String tag = parser.getName(); + if (TAG_ROW.equals(tag)) { + inRow = true; + x = 0; + currentRow = createRowFromXml(res, parser); + rows.add(currentRow); + skipRow = currentRow.mode != 0 && currentRow.mode != mKeyboardMode; + if (skipRow) { + skipToEndOfRow(parser); + inRow = false; + } + } else if (TAG_KEY.equals(tag)) { + inKey = true; + key = createKeyFromXml(res, currentRow, x, y, parser); + mKeys.add(key); + if (key.codes[0] == KEYCODE_SHIFT) { + // Find available shift key slot and put this shift key in it + for (int i = 0; i < mShiftKeys.length; i++) { + if (mShiftKeys[i] == null) { + mShiftKeys[i] = key; + mShiftKeyIndices[i] = mKeys.size()-1; + break; + } + } + mModifierKeys.add(key); + } else if (key.codes[0] == KEYCODE_ALT) { + mModifierKeys.add(key); + } + currentRow.mKeys.add(key); + } else if (TAG_KEYBOARD.equals(tag)) { + parseKeyboardAttributes(res, parser); + } + } else if (event == XmlResourceParser.END_TAG) { + if (inKey) { + inKey = false; + x += key.gap + key.width; + if (x > mTotalWidth) { + mTotalWidth = x; + } + } else if (inRow) { + inRow = false; + y += currentRow.verticalGap; + y += currentRow.defaultHeight; + row++; + } else { + // TODO: error or extend? + } + } + } + } catch (Exception e) { + Log.e(TAG, "Parse error:" + e); + e.printStackTrace(); + } + mTotalHeight = y - mDefaultVerticalGap; + } + + private void skipToEndOfRow(XmlResourceParser parser) + throws XmlPullParserException, IOException { + int event; + while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) { + if (event == XmlResourceParser.END_TAG + && parser.getName().equals(TAG_ROW)) { + break; + } + } + } + + private void parseKeyboardAttributes(Resources res, XmlResourceParser parser) { + TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.style_view); + + mDefaultWidth = getDimensionOrFraction(a, + R.styleable.style_view_android_keyWidth, + mDisplayWidth, mDisplayWidth / 10); + mDefaultHeight = getDimensionOrFraction(a, + R.styleable.style_view_android_keyHeight, + mDisplayHeight, 50); + mDefaultHorizontalGap = getDimensionOrFraction(a, + R.styleable.style_view_android_horizontalGap, + mDisplayWidth, 0); + mDefaultVerticalGap = getDimensionOrFraction(a, + R.styleable.style_view_android_verticalGap, + mDisplayHeight, 0); + mProximityThreshold = (int) (mDefaultWidth * SEARCH_DISTANCE); + mProximityThreshold = mProximityThreshold * mProximityThreshold; // Square it for comparison + a.recycle(); + } + + static int getDimensionOrFraction(TypedArray a, int index, int base, int defValue) { + TypedValue value = a.peekValue(index); + if (value == null) return defValue; + if (value.type == TypedValue.TYPE_DIMENSION) { + return a.getDimensionPixelOffset(index, defValue); + } else if (value.type == TypedValue.TYPE_FRACTION) { + // Round it to avoid values like 47.9999 from getting truncated + return Math.round(a.getFraction(index, base, base, defValue)); + } + return defValue; + } +} + diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/base/LoveKeyBoardView.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/LoveKeyBoardView.java new file mode 100644 index 0000000..ddcb932 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/LoveKeyBoardView.java @@ -0,0 +1,1363 @@ +package com.kb.myapplication.keyboard.choose.base; + + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.widget.PopupWindow; +import android.widget.TextView; + + +import com.kb.myapplication.keyboard.choose.R; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class LoveKeyBoardView extends View implements View.OnClickListener { + + + public interface OnKeyboardActionListener { + + + void onPress(int primaryCode); + + + void onRelease(int primaryCode); + + void onKey(int primaryCode, int[] keyCodes); + + void onText(CharSequence text); + + + void swipeLeft(); + + + void swipeRight(); + + + void swipeDown(); + + + void swipeUp(); + } + + private static final boolean DEBUG = false; + private static final int NOT_A_KEY = -1; + private static final int[] KEY_DELETE = { KeyBoard.KEYCODE_DELETE }; + private static final int[] LONG_PRESSABLE_STATE_SET = { R.styleable.Style_Pre_state_android_state_long_pressable }; + + private Context mContext; + private KeyBoard mKeyboard; + private int mCurrentKeyIndex = NOT_A_KEY; + + private int mLabelTextSize; + private int mKeyTextSize; + private int mKeyTextColor; + private float mShadowRadius; + private int mShadowColor; + private float mBackgroundDimAmount; + + private TextView mPreviewText; + private PopupWindow mPreviewPopup; + private int mPreviewTextSizeLarge; + private int mPreviewOffset; + private int mPreviewHeight; + // Working variable + private final int[] mCoordinates = new int[2]; + + private PopupWindow mPopupKeyboard; + private View mMiniKeyboardContainer; + private LoveKeyBoardView mMiniKeyboard; + private boolean mMiniKeyboardOnScreen; + private View mPopupParent; + private int mMiniKeyboardOffsetX; + private int mMiniKeyboardOffsetY; + private Map mMiniKeyboardCache; + private KeyBoard.Key[] mKeys; + + + private OnKeyboardActionListener mKeyboardActionListener; + + private static final int MSG_SHOW_PREVIEW = 1; + private static final int MSG_REMOVE_PREVIEW = 2; + private static final int MSG_REPEAT = 3; + private static final int MSG_LONGPRESS = 4; + + private static final int DELAY_BEFORE_PREVIEW = 0; + private static final int DELAY_AFTER_PREVIEW = 70; + private static final int DEBOUNCE_TIME = 70; + + private int mVerticalCorrection; + private int mProximityThreshold; + + private boolean mPreviewCentered = false; + private boolean mShowPreview = true; + private boolean mShowTouchPoints = true; + private int mPopupPreviewX; + private int mPopupPreviewY; + + private int mLastX; + private int mLastY; + private int mStartX; + private int mStartY; + + private boolean mProximityCorrectOn; + + private Paint mPaint; + private Rect mPadding; + + private long mDownTime; + private long mLastMoveTime; + private int mLastKey; + private int mLastCodeX; + private int mLastCodeY; + private int mCurrentKey = NOT_A_KEY; + private int mDownKey = NOT_A_KEY; + private long mLastKeyTime; + private long mCurrentKeyTime; + private int[] mKeyIndices = new int[12]; + private GestureDetector mGestureDetector; + private int mPopupX; + private int mPopupY; + private int mRepeatKeyIndex = NOT_A_KEY; + private int mPopupLayout; + private boolean mAbortKey; + private KeyBoard.Key mInvalidatedKey; + private Rect mClipRegion = new Rect(0, 0, 0, 0); + private boolean mPossiblePoly; + private SwipeTracker mSwipeTracker = new SwipeTracker(); + private int mSwipeThreshold; + private boolean mDisambiguateSwipe; + + // Variables for dealing with multiple pointers + private int mOldPointerCount = 1; + private float mOldPointerX; + private float mOldPointerY; + + private Drawable mKeyBackground; + + private static final int REPEAT_INTERVAL = 50; // ~20 keys per second + private static final int REPEAT_START_DELAY = 300; + private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); + + private static int MAX_NEARBY_KEYS = 12; + private int[] mDistances = new int[MAX_NEARBY_KEYS]; + + // For multi-tap + private int mLastSentIndex; + private int mTapCount; + private long mLastTapTime; + private boolean mInMultiTap; + private static final int MULTITAP_INTERVAL = 600; // milliseconds + private StringBuilder mPreviewLabel = new StringBuilder(1); + + /** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/ + private boolean mDrawPending; + /** The dirty region in the keyboard bitmap */ + private Rect mDirtyRect = new Rect(); + /** The keyboard bitmap for faster updates */ + private Bitmap mBuffer; + /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */ + private boolean mKeyboardChanged; + /** The canvas for the above mutable keyboard bitmap */ + private Canvas mCanvas; + /** The accessibility manager for accessibility support */ +// private AccessibilityManager mAccessibilityManager; + /** The audio manager for accessibility support */ + private AudioManager mAudioManager; + /** Whether the requirement of a headset to hear passwords if accessibility is enabled is announced. */ + private boolean mHeadsetRequiredToHearPasswordsAnnounced; + + Handler mHandler; + + public LoveKeyBoardView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public LoveKeyBoardView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public LoveKeyBoardView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + mContext = context; + TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.style_view_keyboard, defStyleAttr, defStyleRes); + + LayoutInflater inflate = + (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + int previewLayout = 0; + int keyTextSize = 0; + + int n = a.getIndexCount(); + + for (int i = 0; i < n; i++) { + int attr = a.getIndex(i); + + if (attr == R.styleable.style_view_keyboard_android_keyBackground) { + mKeyBackground = a.getDrawable(attr); + } else if (attr == R.styleable.style_view_keyboard_android_verticalCorrection) { + mVerticalCorrection = a.getDimensionPixelOffset(attr, 0); + } else if (attr == R.styleable.style_view_keyboard_android_keyPreviewLayout) { + previewLayout = a.getResourceId(attr, 0); + } else if (attr == R.styleable.style_view_keyboard_android_keyPreviewOffset) { + mPreviewOffset = a.getDimensionPixelOffset(attr, 0); + } else if (attr == R.styleable.style_view_keyboard_android_keyPreviewHeight) { + mPreviewHeight = a.getDimensionPixelSize(attr, 80); + } else if (attr == R.styleable.style_view_keyboard_android_keyTextSize) { + mKeyTextSize = a.getDimensionPixelSize(attr, 18); + } else if (attr == R.styleable.style_view_keyboard_android_keyTextColor) { + mKeyTextColor = a.getColor(attr, 0xFF333333); + } else if (attr == R.styleable.style_view_keyboard_android_labelTextSize) { + mLabelTextSize = a.getDimensionPixelSize(attr, 14); + } else if (attr == R.styleable.style_view_keyboard_android_popupLayout) { + mPopupLayout = a.getResourceId(attr, 0); + } else if (attr == R.styleable.style_view_keyboard_android_shadowColor) { + mShadowColor = a.getColor(attr, 0); + } else if (attr == R.styleable.style_view_keyboard_android_shadowRadius) { + mShadowRadius = a.getFloat(attr, 0f); + } + } + + mPreviewPopup = new PopupWindow(context); + if (previewLayout != 0) { + mPreviewText = (TextView) inflate.inflate(previewLayout, null); + mPreviewTextSizeLarge = (int) mPreviewText.getTextSize(); + mPreviewPopup.setContentView(mPreviewText); + mPreviewPopup.setBackgroundDrawable(null); + } else { + mShowPreview = false; + } + + mPreviewPopup.setTouchable(false); + + mPopupKeyboard = new PopupWindow(context); + mPopupKeyboard.setBackgroundDrawable(null); + //mPopupKeyboard.setClippingEnabled(false); + + mPopupParent = this; + //mPredicting = true; + + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setTextSize(keyTextSize); + mPaint.setTextAlign(Paint.Align.CENTER); + mPaint.setAlpha(255); + + mPadding = new Rect(0, 0, 0, 0); + mMiniKeyboardCache = new HashMap(); + mKeyBackground.getPadding(mPadding); + + mSwipeThreshold = (int) (500 * getResources().getDisplayMetrics().density); +// mDisambiguateSwipe = getResources().getBoolean( +// R.bool.config_swipeDisambiguation); + + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + + resetMultiTap(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + initGestureDetector(); + if (mHandler == null) { + mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_SHOW_PREVIEW: + showKey(msg.arg1); + break; + case MSG_REMOVE_PREVIEW: + mPreviewText.setVisibility(INVISIBLE); + break; + case MSG_REPEAT: + if (repeatKey()) { + Message repeat = Message.obtain(this, MSG_REPEAT); + sendMessageDelayed(repeat, REPEAT_INTERVAL); + } + break; + case MSG_LONGPRESS: + openPopupIfRequired((MotionEvent) msg.obj); + break; + } + } + }; + } + } + + private void initGestureDetector() { + if (mGestureDetector == null) { + mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onFling(MotionEvent me1, MotionEvent me2, + float velocityX, float velocityY) { + if (mPossiblePoly) return false; + final float absX = Math.abs(velocityX); + final float absY = Math.abs(velocityY); + float deltaX = me2.getX() - me1.getX(); + float deltaY = me2.getY() - me1.getY(); + int travelX = getWidth() / 2; // Half the keyboard width + int travelY = getHeight() / 2; // Half the keyboard height + mSwipeTracker.computeCurrentVelocity(1000); + final float endingVelocityX = mSwipeTracker.getXVelocity(); + final float endingVelocityY = mSwipeTracker.getYVelocity(); + boolean sendDownKey = false; + if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) { + if (mDisambiguateSwipe && endingVelocityX < velocityX / 4) { + sendDownKey = true; + } else { + swipeRight(); + return true; + } + } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) { + if (mDisambiguateSwipe && endingVelocityX > velocityX / 4) { + sendDownKey = true; + } else { + swipeLeft(); + return true; + } + } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) { + if (mDisambiguateSwipe && endingVelocityY > velocityY / 4) { + sendDownKey = true; + } else { + swipeUp(); + return true; + } + } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) { + if (mDisambiguateSwipe && endingVelocityY < velocityY / 4) { + sendDownKey = true; + } else { + swipeDown(); + return true; + } + } + + if (sendDownKey) { + detectAndSendKey(mDownKey, mStartX, mStartY, me1.getEventTime()); + } + return false; + } + }); + + mGestureDetector.setIsLongpressEnabled(false); + } + } + + public void setOnKeyboardActionListener(OnKeyboardActionListener listener) { + mKeyboardActionListener = listener; + } + + protected OnKeyboardActionListener getOnKeyboardActionListener() { + return mKeyboardActionListener; + } + + + public void setKeyboard(KeyBoard keyboard) { + if (mKeyboard != null) { + showPreview(NOT_A_KEY); + } + // Remove any pending messages + removeMessages(); + mKeyboard = keyboard; + List keys = mKeyboard.getKeys(); + mKeys = keys.toArray(new KeyBoard.Key[keys.size()]); + requestLayout(); + // Hint to reallocate the buffer if the size changed + mKeyboardChanged = true; + invalidateAllKeys(); + computeProximityThreshold(keyboard); + mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views + // Switching to a different keyboard should abort any pending keys so that the key up + // doesn't get delivered to the old or new keyboard + mAbortKey = true; // Until the next ACTION_DOWN + } + + + public KeyBoard getKeyboard() { + return mKeyboard; + } + + + public boolean setShifted(boolean shifted) { + if (mKeyboard != null) { + if (mKeyboard.setShifted(shifted)) { + // The whole keyboard probably needs to be redrawn + invalidateAllKeys(); + return true; + } + } + return false; + } + + + public boolean isShifted() { + if (mKeyboard != null) { + return mKeyboard.isShifted(); + } + return false; + } + + + public void setPreviewEnabled(boolean previewEnabled) { + mShowPreview = previewEnabled; + } + + /** + * Returns the enabled state of the key feedback popup. + * @return whether or not the key feedback popup is enabled + * @see #setPreviewEnabled(boolean) + */ + public boolean isPreviewEnabled() { + return mShowPreview; + } + + public void setVerticalCorrection(int verticalOffset) { + + } + public void setPopupParent(View v) { + mPopupParent = v; + } + + public void setPopupOffset(int x, int y) { + mMiniKeyboardOffsetX = x; + mMiniKeyboardOffsetY = y; + if (mPreviewPopup.isShowing()) { + mPreviewPopup.dismiss(); + } + } + + public void setProximityCorrectionEnabled(boolean enabled) { + mProximityCorrectOn = enabled; + } + + /** + * Returns true if proximity correction is enabled. + */ + public boolean isProximityCorrectionEnabled() { + return mProximityCorrectOn; + } + + /** + * Popup keyboard close button clicked. + * @hide + */ + public void onClick(View v) { + dismissPopupKeyboard(); + } + + private CharSequence adjustCase(CharSequence label) { + if (mKeyboard.isShifted() && label != null && label.length() < 3 + && Character.isLowerCase(label.charAt(0))) { + label = label.toString().toUpperCase(); + } + return label; + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Round up a little + if (mKeyboard == null) { + setMeasuredDimension(getPaddingLeft() + getPaddingRight(), getPaddingTop() + getPaddingBottom()); + } else { + int width = mKeyboard.getMinWidth() + getPaddingLeft() + getPaddingRight(); + if (MeasureSpec.getSize(widthMeasureSpec) < width + 10) { + width = MeasureSpec.getSize(widthMeasureSpec); + } + setMeasuredDimension(width, mKeyboard.getHeight() + getPaddingTop() + getPaddingBottom()); + } + } + + /** + * Compute the average distance between adjacent keys (horizontally and vertically) + * and square it to get the proximity threshold. We use a square here and in computing + * the touch distance from a key's center to avoid taking a square root. + * @param keyboard + */ + private void computeProximityThreshold(KeyBoard keyboard) { + if (keyboard == null) return; + final KeyBoard.Key[] keys = mKeys; + if (keys == null) return; + int length = keys.length; + int dimensionSum = 0; + for (int i = 0; i < length; i++) { + KeyBoard.Key key = keys[i]; + dimensionSum += Math.min(key.width, key.height) + key.gap; + } + if (dimensionSum < 0 || length == 0) return; + mProximityThreshold = (int) (dimensionSum * 1.4f / length); + mProximityThreshold *= mProximityThreshold; // Square it + } + + @Override + public void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (mKeyboard != null) { + mKeyboard.resize(w, h); + } + // Release the buffer, if any and it will be reallocated on the next draw + mBuffer = null; + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); +// if (mDrawPending || mBuffer == null || mKeyboardChanged) { +// onBufferDraw(); +// } +// canvas.drawBitmap(mBuffer, 0, 0, null); + } + + private void onBufferDraw() { + if (mBuffer == null || mKeyboardChanged) { + if (mBuffer == null || mKeyboardChanged && + (mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) { + // Make sure our bitmap is at least 1x1 + final int width = Math.max(1, getWidth()); + final int height = Math.max(1, getHeight()); + mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + mCanvas = new Canvas(mBuffer); + } + invalidateAllKeys(); + mKeyboardChanged = false; + } + + if (mKeyboard == null) return; + + mCanvas.save(); + final Canvas canvas = mCanvas; + canvas.clipRect(mDirtyRect); + + final Paint paint = mPaint; + final Drawable keyBackground = mKeyBackground; + final Rect clipRegion = mClipRegion; + final Rect padding = mPadding; + final int kbdPaddingLeft = getPaddingLeft(); + final int kbdPaddingTop = getPaddingTop(); + final KeyBoard.Key[] keys = mKeys; + final KeyBoard.Key invalidKey = mInvalidatedKey; + + paint.setColor(mKeyTextColor); + boolean drawSingleKey = false; + if (invalidKey != null && canvas.getClipBounds(clipRegion)) { + // Is clipRegion completely contained within the invalidated key? + if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left && + invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top && + invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right && + invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) { + drawSingleKey = true; + } + } + canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); + final int keyCount = keys.length; + for (int i = 0; i < keyCount; i++) { + final KeyBoard.Key key = keys[i]; + if (drawSingleKey && invalidKey != key) { + continue; + } + int[] drawableState = key.getCurrentDrawableState(); + keyBackground.setState(drawableState); + + // Switch the character to uppercase if shift is pressed + String label = key.label == null? null : adjustCase(key.label).toString(); + + final Rect bounds = keyBackground.getBounds(); + if (key.width != bounds.right || + key.height != bounds.bottom) { + keyBackground.setBounds(0, 0, key.width, key.height); + } + canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop); + keyBackground.draw(canvas); + + if (label != null) { + // For characters, use large font. For labels like "Done", use small font. + if (label.length() > 1 && key.codes.length < 2) { + paint.setTextSize(mLabelTextSize); + paint.setTypeface(Typeface.DEFAULT_BOLD); + } else { + paint.setTextSize(mKeyTextSize); + paint.setTypeface(Typeface.DEFAULT); + } + // Draw a drop shadow for the text + paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor); + // Draw the text + canvas.drawText(label, + (key.width - padding.left - padding.right) / 2 + + padding.left, + (key.height - padding.top - padding.bottom) / 2 + + (paint.getTextSize() - paint.descent()) / 2 + padding.top, + paint); + // Turn off drop shadow + paint.setShadowLayer(0, 0, 0, 0); + } else if (key.icon != null) { + final int drawableX = (key.width - padding.left - padding.right + - key.icon.getIntrinsicWidth()) / 2 + padding.left; + final int drawableY = (key.height - padding.top - padding.bottom + - key.icon.getIntrinsicHeight()) / 2 + padding.top; + canvas.translate(drawableX, drawableY); + key.icon.setBounds(0, 0, + key.icon.getIntrinsicWidth(), key.icon.getIntrinsicHeight()); + key.icon.draw(canvas); + canvas.translate(-drawableX, -drawableY); + } + canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop); + } + mInvalidatedKey = null; + // Overlay a dark rectangle to dim the keyboard + if (mMiniKeyboardOnScreen) { +// paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); + canvas.drawRect(0, 0, getWidth(), getHeight(), paint); + } + + if (DEBUG && mShowTouchPoints) { + paint.setAlpha(128); + paint.setColor(0xFFFF0000); + canvas.drawCircle(mStartX, mStartY, 3, paint); + canvas.drawLine(mStartX, mStartY, mLastX, mLastY, paint); + paint.setColor(0xFF0000FF); + canvas.drawCircle(mLastX, mLastY, 3, paint); + paint.setColor(0xFF00FF00); + canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint); + } + mCanvas.restore(); + mDrawPending = false; + mDirtyRect.setEmpty(); + } + + private int getKeyIndices(int x, int y, int[] allKeys) { + final KeyBoard.Key[] keys = mKeys; + int primaryIndex = NOT_A_KEY; + int closestKey = NOT_A_KEY; + int closestKeyDist = mProximityThreshold + 1; + Arrays.fill(mDistances, Integer.MAX_VALUE); + int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y); + final int keyCount = nearestKeyIndices.length; + for (int i = 0; i < keyCount; i++) { + final KeyBoard.Key key = keys[nearestKeyIndices[i]]; + int dist = 0; + boolean isInside = key.isInside(x,y); + if (isInside) { + primaryIndex = nearestKeyIndices[i]; + } + + if (((mProximityCorrectOn + && (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold) + || isInside) + && key.codes[0] > 32) { + // Find insertion point + final int nCodes = key.codes.length; + if (dist < closestKeyDist) { + closestKeyDist = dist; + closestKey = nearestKeyIndices[i]; + } + + if (allKeys == null) continue; + + for (int j = 0; j < mDistances.length; j++) { + if (mDistances[j] > dist) { + // Make space for nCodes codes + System.arraycopy(mDistances, j, mDistances, j + nCodes, + mDistances.length - j - nCodes); + System.arraycopy(allKeys, j, allKeys, j + nCodes, + allKeys.length - j - nCodes); + for (int c = 0; c < nCodes; c++) { + allKeys[j + c] = key.codes[c]; + mDistances[j + c] = dist; + } + break; + } + } + } + } + if (primaryIndex == NOT_A_KEY) { + primaryIndex = closestKey; + } + return primaryIndex; + } + + private void detectAndSendKey(int index, int x, int y, long eventTime) { + if (index != NOT_A_KEY && index < mKeys.length) { + final KeyBoard.Key key = mKeys[index]; + if (key.text != null) { + mKeyboardActionListener.onText(key.text); + mKeyboardActionListener.onRelease(NOT_A_KEY); + } else { + int code = key.codes[0]; + //TextEntryState.keyPressedAt(key, x, y); + int[] codes = new int[MAX_NEARBY_KEYS]; + Arrays.fill(codes, NOT_A_KEY); + getKeyIndices(x, y, codes); + // Multi-tap + if (mInMultiTap) { + if (mTapCount != -1) { + mKeyboardActionListener.onKey(KeyBoard.KEYCODE_DELETE, KEY_DELETE); + } else { + mTapCount = 0; + } + code = key.codes[mTapCount]; + } + mKeyboardActionListener.onKey(code, codes); + mKeyboardActionListener.onRelease(code); + } + mLastSentIndex = index; + mLastTapTime = eventTime; + } + } + + + private CharSequence getPreviewText(KeyBoard.Key key) { + if (mInMultiTap) { + // Multi-tap + mPreviewLabel.setLength(0); + mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]); + return adjustCase(mPreviewLabel); + } else { + return adjustCase(key.label); + } + } + + private void showPreview(int keyIndex) { + int oldKeyIndex = mCurrentKeyIndex; + final PopupWindow previewPopup = mPreviewPopup; + + mCurrentKeyIndex = keyIndex; + // Release the old key and press the new key + final KeyBoard.Key[] keys = mKeys; + if (oldKeyIndex != mCurrentKeyIndex) { + if (oldKeyIndex != NOT_A_KEY && keys.length > oldKeyIndex) { + KeyBoard.Key oldKey = keys[oldKeyIndex]; + oldKey.onReleased(mCurrentKeyIndex == NOT_A_KEY); + invalidateKey(oldKeyIndex); + final int keyCode = oldKey.codes[0]; + } + if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) { + KeyBoard.Key newKey = keys[mCurrentKeyIndex]; + newKey.onPressed(); + invalidateKey(mCurrentKeyIndex); + final int keyCode = newKey.codes[0]; + } + } + // If key changed and preview is on ... + if (oldKeyIndex != mCurrentKeyIndex && mShowPreview) { + mHandler.removeMessages(MSG_SHOW_PREVIEW); + if (previewPopup.isShowing()) { + if (keyIndex == NOT_A_KEY) { + mHandler.sendMessageDelayed(mHandler + .obtainMessage(MSG_REMOVE_PREVIEW), + DELAY_AFTER_PREVIEW); + } + } + if (keyIndex != NOT_A_KEY) { + if (previewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) { + // Show right away, if it's already visible and finger is moving around + showKey(keyIndex); + } else { + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0), + DELAY_BEFORE_PREVIEW); + } + } + } + } + + private void showKey(final int keyIndex) { + final PopupWindow previewPopup = mPreviewPopup; + final KeyBoard.Key[] keys = mKeys; + if (keyIndex < 0 || keyIndex >= mKeys.length) return; + KeyBoard.Key key = keys[keyIndex]; + if (key.icon != null) { + mPreviewText.setCompoundDrawables(null, null, null, + key.iconPreview != null ? key.iconPreview : key.icon); + mPreviewText.setText(null); + } else { + mPreviewText.setCompoundDrawables(null, null, null, null); + mPreviewText.setText(getPreviewText(key)); + if (key.label!=null && key.label.length() > 1 && key.codes.length < 2) { + mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize); + mPreviewText.setTypeface(Typeface.DEFAULT_BOLD); + } else { + mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSizeLarge); + mPreviewText.setTypeface(Typeface.DEFAULT); + } + } + mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width + + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight()); + final int popupHeight = mPreviewHeight; + ViewGroup.LayoutParams lp = mPreviewText.getLayoutParams(); + if (lp != null) { + lp.width = popupWidth; + lp.height = popupHeight; + } + if (!mPreviewCentered) { + mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + getPaddingLeft(); + mPopupPreviewY = key.y - popupHeight + mPreviewOffset; + } else { + + mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2; + mPopupPreviewY = - mPreviewText.getMeasuredHeight(); + } + mHandler.removeMessages(MSG_REMOVE_PREVIEW); + getLocationInWindow(mCoordinates); + mCoordinates[0] += mMiniKeyboardOffsetX; // Offset may be zero + mCoordinates[1] += mMiniKeyboardOffsetY; // Offset may be zero + + + mPreviewText.getBackground().setState( + key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); + mPopupPreviewX += mCoordinates[0]; + mPopupPreviewY += mCoordinates[1]; + + + getLocationOnScreen(mCoordinates); + if (mPopupPreviewY + mCoordinates[1] < 0) { + + if (key.x + key.width <= getWidth() / 2) { + mPopupPreviewX += (int) (key.width * 2.5); + } else { + mPopupPreviewX -= (int) (key.width * 2.5); + } + mPopupPreviewY += popupHeight; + } + + if (previewPopup.isShowing()) { + previewPopup.update(mPopupPreviewX, mPopupPreviewY, + popupWidth, popupHeight); + } else { + previewPopup.setWidth(popupWidth); + previewPopup.setHeight(popupHeight); + previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY, + mPopupPreviewX, mPopupPreviewY); + } + mPreviewText.setVisibility(VISIBLE); + } + + + public void invalidateAllKeys() { + mDirtyRect.union(0, 0, getWidth(), getHeight()); + mDrawPending = true; + invalidate(); + } + + + public void invalidateKey(int keyIndex) { + if (mKeys == null) return; + if (keyIndex < 0 || keyIndex >= mKeys.length) { + return; + } + final KeyBoard.Key key = mKeys[keyIndex]; + mInvalidatedKey = key; + mDirtyRect.union(key.x + getPaddingLeft(), key.y + getPaddingTop(), + key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop()); + onBufferDraw(); + invalidate(key.x + getPaddingLeft(), key.y + getPaddingTop(), + key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop()); + } + + private boolean openPopupIfRequired(MotionEvent me) { + // Check if we have a popup layout specified first. + if (mPopupLayout == 0) { + return false; + } + if (mCurrentKey < 0 || mCurrentKey >= mKeys.length) { + return false; + } + + KeyBoard.Key popupKey = mKeys[mCurrentKey]; + boolean result = onLongPress(popupKey); + if (result) { + mAbortKey = true; + showPreview(NOT_A_KEY); + } + return result; + } + + protected boolean onLongPress(KeyBoard.Key popupKey) { + int popupKeyboardId = popupKey.popupResId; + + if (popupKeyboardId != 0) { + mMiniKeyboardContainer = mMiniKeyboardCache.get(popupKey); + if (mMiniKeyboardContainer == null) { + LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + mMiniKeyboardContainer = inflater.inflate(mPopupLayout, null); + mMiniKeyboard = mMiniKeyboardContainer.findViewById( + R.id.my_keyboard_input); + mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() { + public void onKey(int primaryCode, int[] keyCodes) { + mKeyboardActionListener.onKey(primaryCode, keyCodes); + dismissPopupKeyboard(); + } + + public void onText(CharSequence text) { + mKeyboardActionListener.onText(text); + dismissPopupKeyboard(); + } + + public void swipeLeft() { } + public void swipeRight() { } + public void swipeUp() { } + public void swipeDown() { } + public void onPress(int primaryCode) { + mKeyboardActionListener.onPress(primaryCode); + } + public void onRelease(int primaryCode) { + mKeyboardActionListener.onRelease(primaryCode); + } + }); + //mInputView.setSuggest(mSuggest); + KeyBoard keyboard; + if (popupKey.popupCharacters != null) { + keyboard = new KeyBoard(getContext(), popupKeyboardId, + popupKey.popupCharacters, -1, getPaddingLeft() + getPaddingRight()); + } else { + keyboard = new KeyBoard(getContext(), popupKeyboardId); + } + mMiniKeyboard.setKeyboard(keyboard); + mMiniKeyboard.setPopupParent(this); + mMiniKeyboardContainer.measure( + MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); + + mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer); + } else { + mMiniKeyboard = mMiniKeyboardContainer.findViewById( + R.id.my_keyboard_input); + } + getLocationInWindow(mCoordinates); + mPopupX = popupKey.x + getPaddingLeft(); + mPopupY = popupKey.y + getPaddingTop(); + mPopupX = mPopupX + popupKey.width - mMiniKeyboardContainer.getMeasuredWidth(); + mPopupY = mPopupY - mMiniKeyboardContainer.getMeasuredHeight(); + final int x = mPopupX + mMiniKeyboardContainer.getPaddingRight() + mCoordinates[0]; + final int y = mPopupY + mMiniKeyboardContainer.getPaddingBottom() + mCoordinates[1]; + mMiniKeyboard.setPopupOffset(x < 0 ? 0 : x, y); + mMiniKeyboard.setShifted(isShifted()); + mPopupKeyboard.setContentView(mMiniKeyboardContainer); + mPopupKeyboard.setWidth(mMiniKeyboardContainer.getMeasuredWidth()); + mPopupKeyboard.setHeight(mMiniKeyboardContainer.getMeasuredHeight()); + mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y); + mMiniKeyboardOnScreen = true; + invalidateAllKeys(); + return true; + } + return false; + } + + + + @Override + public boolean onTouchEvent(MotionEvent me) { + // Convert multi-pointer up/down events to single up/down events to + // deal with the typical multi-pointer behavior of two-thumb typing + final int pointerCount = me.getPointerCount(); + final int action = me.getAction(); + boolean result = false; + final long now = me.getEventTime(); + + if (pointerCount != mOldPointerCount) { + if (pointerCount == 1) { + // Send a down event for the latest pointer + MotionEvent down = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, + me.getX(), me.getY(), me.getMetaState()); + result = onModifiedTouchEvent(down, false); + down.recycle(); + // If it's an up action, then deliver the up as well. + if (action == MotionEvent.ACTION_UP) { + result = onModifiedTouchEvent(me, true); + } + } else { + // Send an up event for the last pointer + MotionEvent up = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, + mOldPointerX, mOldPointerY, me.getMetaState()); + result = onModifiedTouchEvent(up, true); + up.recycle(); + } + } else { + if (pointerCount == 1) { + result = onModifiedTouchEvent(me, false); + mOldPointerX = me.getX(); + mOldPointerY = me.getY(); + } else { + // Don't do anything when 2 pointers are down and moving. + result = true; + } + } + mOldPointerCount = pointerCount; + + + return result; + } + + private boolean onModifiedTouchEvent(MotionEvent me, boolean possiblePoly) { + int touchX = (int) me.getX() - getPaddingLeft(); + int touchY = (int) me.getY() - getPaddingTop(); + if (touchY >= -mVerticalCorrection) + touchY += mVerticalCorrection; + final int action = me.getAction(); + final long eventTime = me.getEventTime(); + int keyIndex = getKeyIndices(touchX, touchY, null); + mPossiblePoly = possiblePoly; + + // Track the last few movements to look for spurious swipes. + if (action == MotionEvent.ACTION_DOWN) mSwipeTracker.clear(); + mSwipeTracker.addMovement(me); + + // Ignore all motion events until a DOWN. + if (mAbortKey + && action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_CANCEL) { + mRepeatKeyIndex = NOT_A_KEY; + return true; + } + + if (mGestureDetector.onTouchEvent(me)) { + showPreview(NOT_A_KEY); + mHandler.removeMessages(MSG_REPEAT); + mHandler.removeMessages(MSG_LONGPRESS); + return true; + } + + // Needs to be called after the gesture detector gets a turn, as it may have + // displayed the mini keyboard + if (mMiniKeyboardOnScreen && action != MotionEvent.ACTION_CANCEL) { + mRepeatKeyIndex = NOT_A_KEY; + return true; + } + + switch (action) { + case MotionEvent.ACTION_DOWN: + mAbortKey = false; + mStartX = touchX; + mStartY = touchY; + mLastCodeX = touchX; + mLastCodeY = touchY; + mLastKeyTime = 0; + mCurrentKeyTime = 0; + mLastKey = NOT_A_KEY; + mCurrentKey = keyIndex; + mDownKey = keyIndex; + mDownTime = me.getEventTime(); + mLastMoveTime = mDownTime; + checkMultiTap(eventTime, keyIndex); + mKeyboardActionListener.onPress(keyIndex != NOT_A_KEY ? + mKeys[keyIndex].codes[0] : 0); + if (mCurrentKey >= 0 && mKeys[mCurrentKey].repeatable) { + mRepeatKeyIndex = mCurrentKey; + Message msg = mHandler.obtainMessage(MSG_REPEAT); + mHandler.sendMessageDelayed(msg, REPEAT_START_DELAY); + repeatKey(); + // Delivering the key could have caused an abort + if (mAbortKey) { + mRepeatKeyIndex = NOT_A_KEY; + break; + } + } + if (mCurrentKey != NOT_A_KEY) { + Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me); + mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT); + } + showPreview(keyIndex); + break; + + case MotionEvent.ACTION_MOVE: + boolean continueLongPress = false; + if (keyIndex != NOT_A_KEY) { + if (mCurrentKey == NOT_A_KEY) { + mCurrentKey = keyIndex; + mCurrentKeyTime = eventTime - mDownTime; + } else { + if (keyIndex == mCurrentKey) { + mCurrentKeyTime += eventTime - mLastMoveTime; + continueLongPress = true; + } else if (mRepeatKeyIndex == NOT_A_KEY) { + resetMultiTap(); + mLastKey = mCurrentKey; + mLastCodeX = mLastX; + mLastCodeY = mLastY; + mLastKeyTime = + mCurrentKeyTime + eventTime - mLastMoveTime; + mCurrentKey = keyIndex; + mCurrentKeyTime = 0; + } + } + } + if (!continueLongPress) { + // Cancel old longpress + mHandler.removeMessages(MSG_LONGPRESS); + // Start new longpress if key has changed + if (keyIndex != NOT_A_KEY) { + Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me); + mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT); + } + } + showPreview(mCurrentKey); + mLastMoveTime = eventTime; + break; + + case MotionEvent.ACTION_UP: + removeMessages(); + if (keyIndex == mCurrentKey) { + mCurrentKeyTime += eventTime - mLastMoveTime; + } else { + resetMultiTap(); + mLastKey = mCurrentKey; + mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime; + mCurrentKey = keyIndex; + mCurrentKeyTime = 0; + } + if (mCurrentKeyTime < mLastKeyTime && mCurrentKeyTime < DEBOUNCE_TIME + && mLastKey != NOT_A_KEY) { + mCurrentKey = mLastKey; + touchX = mLastCodeX; + touchY = mLastCodeY; + } + showPreview(NOT_A_KEY); + Arrays.fill(mKeyIndices, NOT_A_KEY); + // If we're not on a repeating key (which sends on a DOWN event) + if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) { + detectAndSendKey(mCurrentKey, touchX, touchY, eventTime); + } + invalidateKey(keyIndex); + mRepeatKeyIndex = NOT_A_KEY; + break; + case MotionEvent.ACTION_CANCEL: + removeMessages(); + dismissPopupKeyboard(); + mAbortKey = true; + showPreview(NOT_A_KEY); + invalidateKey(mCurrentKey); + break; + } + mLastX = touchX; + mLastY = touchY; + return true; + } + + private boolean repeatKey() { + if(mRepeatKeyIndex != NOT_A_KEY){ + KeyBoard.Key key = mKeys[mRepeatKeyIndex]; + detectAndSendKey(mCurrentKey, key.x, key.y, mLastTapTime); + return true; + } + return false; + } + + protected void swipeRight() { + mKeyboardActionListener.swipeRight(); + } + + protected void swipeLeft() { + mKeyboardActionListener.swipeLeft(); + } + + protected void swipeUp() { + mKeyboardActionListener.swipeUp(); + } + + protected void swipeDown() { + mKeyboardActionListener.swipeDown(); + } + + public void closing() { + if (mPreviewPopup.isShowing()) { + mPreviewPopup.dismiss(); + } + removeMessages(); + + dismissPopupKeyboard(); + mBuffer = null; + mCanvas = null; + mMiniKeyboardCache.clear(); + } + + private void removeMessages() { + if (mHandler != null) { + mHandler.removeMessages(MSG_REPEAT); + mHandler.removeMessages(MSG_LONGPRESS); + mHandler.removeMessages(MSG_SHOW_PREVIEW); + } + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + closing(); + } + + private void dismissPopupKeyboard() { + if (mPopupKeyboard.isShowing()) { + mPopupKeyboard.dismiss(); + mMiniKeyboardOnScreen = false; + invalidateAllKeys(); + } + } + + public boolean handleBack() { + if (mPopupKeyboard.isShowing()) { + dismissPopupKeyboard(); + return true; + } + return false; + } + + private void resetMultiTap() { + mLastSentIndex = NOT_A_KEY; + mTapCount = 0; + mLastTapTime = -1; + mInMultiTap = false; + } + + private void checkMultiTap(long eventTime, int keyIndex) { + if (keyIndex == NOT_A_KEY) return; + KeyBoard.Key key = mKeys[keyIndex]; + if (key.codes.length > 1) { + mInMultiTap = true; + if (eventTime < mLastTapTime + MULTITAP_INTERVAL + && keyIndex == mLastSentIndex) { + mTapCount = (mTapCount + 1) % key.codes.length; + return; + } else { + mTapCount = -1; + return; + } + } + if (eventTime > mLastTapTime + MULTITAP_INTERVAL || keyIndex != mLastSentIndex) { + resetMultiTap(); + } + } + + private static class SwipeTracker { + + static final int NUM_PAST = 4; + static final int LONGEST_PAST_TIME = 200; + + final float mPastX[] = new float[NUM_PAST]; + final float mPastY[] = new float[NUM_PAST]; + final long mPastTime[] = new long[NUM_PAST]; + + float mYVelocity; + float mXVelocity; + + public void clear() { + mPastTime[0] = 0; + } + + public void addMovement(MotionEvent ev) { + long time = ev.getEventTime(); + final int N = ev.getHistorySize(); + for (int i=0; i= 0) { + final int start = drop+1; + final int count = NUM_PAST-drop-1; + System.arraycopy(pastX, start, pastX, 0, count); + System.arraycopy(pastY, start, pastY, 0, count); + System.arraycopy(pastTime, start, pastTime, 0, count); + i -= (drop+1); + } + pastX[i] = x; + pastY[i] = y; + pastTime[i] = time; + i++; + if (i < NUM_PAST) { + pastTime[i] = 0; + } + } + + public void computeCurrentVelocity(int units) { + computeCurrentVelocity(units, Float.MAX_VALUE); + } + + public void computeCurrentVelocity(int units, float maxVelocity) { + final float[] pastX = mPastX; + final float[] pastY = mPastY; + final long[] pastTime = mPastTime; + + final float oldestX = pastX[0]; + final float oldestY = pastY[0]; + final long oldestTime = pastTime[0]; + float accumX = 0; + float accumY = 0; + int N=0; + while (N < NUM_PAST) { + if (pastTime[N] == 0) { + break; + } + N++; + } + + for (int i=1; i < N; i++) { + final int dur = (int)(pastTime[i] - oldestTime); + if (dur == 0) continue; + float dist = pastX[i] - oldestX; + float vel = (dist/dur) * units; // pixels/frame. + if (accumX == 0) accumX = vel; + else accumX = (accumX + vel) * .5f; + + dist = pastY[i] - oldestY; + vel = (dist/dur) * units; // pixels/frame. + if (accumY == 0) accumY = vel; + else accumY = (accumY + vel) * .5f; + } + mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) + : Math.min(accumX, maxVelocity); + mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) + : Math.min(accumY, maxVelocity); + } + + public float getXVelocity() { + return mXVelocity; + } + + public float getYVelocity() { + return mYVelocity; + } + } +} + diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/base/MyLoveKeyBoardView.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/MyLoveKeyBoardView.java new file mode 100644 index 0000000..51db084 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/MyLoveKeyBoardView.java @@ -0,0 +1,158 @@ +package com.kb.myapplication.keyboard.choose.base; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; + +import com.kb.myapplication.keyboard.choose.MyTools; +import java.util.List; + +public class MyLoveKeyBoardView extends LoveKeyBoardView { + + private CustomViewConfig config = new CustomViewConfig(); + private int shift_status = 0; + private int viewType = 0; + + private Context context; + + public void setShift_status(int shift_status) { + this.shift_status = shift_status; + } + + public int getShift_status() { + return shift_status; + } + + public void setViewType(int viewType) { + this.viewType = viewType; + } + + public int getViewType() { + return viewType; + } + + public MyLoveKeyBoardView(Context context, AttributeSet attrs) { + + super(context, attrs); + initView(); + } + + public MyLoveKeyBoardView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initView(); + } + + public MyLoveKeyBoardView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initView(); + } + + + private Paint mPaint; + + + private void initView() { + config.init(); + context = getContext(); + mPaint = new Paint(); + mPaint.setTextAlign(Paint.Align.CENTER); + float textSize = MyTools.spToPpx(16f, context); + mPaint.setTextSize(textSize); + mPaint.setColor(config.getKeyNoramlcolor()); + } + + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + + KeyBoard keyboard = getKeyboard(); + List keys = keyboard.getKeys(); + for (int r = 0; r < keys.size(); r++) { + KeyBoard.Key key = keys.get(r); + int code = key.codes[0]; + + mPaint.setColor(config.getKeyActioncolor()); + if (code == KeyBoard.KEYCODE_MODE_CHANGE) { + + onDrawKeyBackground(key, config.getBgActionDraw(), canvas); + onDrawLabel(key, canvas); + + } else if (code == KeyBoard.KEYCODE_SHIFT) { + onDrawKeyBackground(key, config.getBgActionDraw(), canvas); + DrawIcon.INSTANCE.onDrawKeyIcon(key, getShiftDraw(), canvas, this); + + } else if (code == KeyBoard.KEYCODE_SHIFT_123) { + + onDrawKeyBackground(key, config.getBgActionDraw(), canvas); +// DrawIcon.INSTANCE.onDrawKeyIcon(key, getShiftDraw(), canvas, this); + onDrawLabel(key, canvas); + + } else if (code == KeyBoard.KEYCODE_SHIFT_SYMBOL) { + + onDrawKeyBackground(key, config.getBgActionDraw(), canvas); +// DrawIcon.INSTANCE.onDrawKeyIcon(key, getShiftDraw(), canvas, this); + onDrawLabel(key, canvas); + + } else if (code == KeyBoard.KEYCODE_DONE) { + onDrawKeyBackground(key, config.getBgActionDraw(), canvas); + onDrawLabel(key, canvas); + } else if (code == KeyBoard.KEYCODE_DELETE) { + + onDrawKeyBackground(key, config.getBgActionDraw(), canvas); + DrawIcon.INSTANCE.onDrawKeyIcon(key, config.getIconDel(), canvas, this); + onDrawLabel(key, canvas); + } else { + mPaint.setColor(config.getKeyNoramlcolor()); + onDrawKeyBackground(key, config.getBgNormalDraw(), canvas); + onDrawLabel(key, canvas); + } + } + + } + + public void updateConfigView(Context con) { + config.updateConfig(con); + setBackground(config.getBG()); + invalidateAllKeys(); + + } + + private Drawable getShiftDraw() { + if (shift_status == 0) { + return config.getIconShift(); + } else if (shift_status == 1) { + return config.getIconShiftLock(); + } else { + return config.getIconShiftLock(); + } + } + + + private void onDrawKeyBackground(KeyBoard.Key myKey, + Drawable keyBG, + Canvas canvas) { + if (keyBG != null) { + Rect rect = new Rect(myKey.x + getPaddingLeft(), myKey.y + getPaddingTop(), myKey.width + myKey.x + getPaddingLeft(), myKey.height + myKey.y + getPaddingTop()); + keyBG.setBounds(rect); + keyBG.setState(myKey.getCurrentDrawableState()); + keyBG.draw(canvas); + } + } + + private void onDrawLabel( + KeyBoard.Key myKey, + Canvas canvas) { + boolean b = myKey.label == null || myKey.label == ""; + if (!b) { + float y1 = myKey.y + getPaddingRight() + (myKey.height/ 2f) + ((mPaint.getTextSize() - mPaint.descent()) / 2f); + float x1 = myKey.x + getPaddingLeft() + ((myKey.width / 2f)); + canvas.drawText(myKey.label.toString(), x1, y1, mPaint); + + } + } + +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/base/MySpace.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/MySpace.java new file mode 100644 index 0000000..fd878c5 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/MySpace.java @@ -0,0 +1,56 @@ +package com.kb.myapplication.keyboard.choose.base; + +import android.graphics.Rect; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +public class MySpace extends RecyclerView.ItemDecoration { + private int ex_space = 0; + private int v_space = 0; + private int h_space = 0; + + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + + int position = parent.getChildAdapterPosition(view); + int spanSize = 1; + int spanIndex = 0; + int spanCount = 1; + + RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); + + if (layoutManager instanceof GridLayoutManager) { + GridLayoutManager layoutManager1 = (GridLayoutManager) layoutManager; + GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams(); + spanCount = layoutManager1.getSpanCount(); + spanSize = layoutManager1.getSpanSizeLookup().getSpanSize(position); + spanIndex = layoutParams.getSpanIndex(); + + } + + + if (spanSize == spanCount) { + outRect.left = v_space + ex_space; + outRect.right = v_space + ex_space; + outRect.bottom = h_space; + } else { + int itemAllSpacing = (v_space * (spanCount + 1) + ex_space * 2) / spanCount; + int left = v_space * (spanIndex + 1) - itemAllSpacing * spanIndex + ex_space; + int right = itemAllSpacing - left; + outRect.left = left; + outRect.right = right; + outRect.bottom = h_space; + } + + } + + public MySpace(int v_space, int h_space, int ex_space) { + this.ex_space = ex_space; + this.h_space = h_space; + this.v_space = v_space; + + } +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/base/ServiceDialog.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/ServiceDialog.java new file mode 100644 index 0000000..be6e109 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/base/ServiceDialog.java @@ -0,0 +1,93 @@ +package com.kb.myapplication.keyboard.choose.base; + + +import static androidx.core.content.ContextCompat.getColor; +import static androidx.core.content.ContextCompat.registerReceiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import com.kb.myapplication.keyboard.choose.MyTools; +import com.kb.myapplication.keyboard.choose.R; +import com.kb.myapplication.keyboard.choose.activity.MainActivity; +import com.kb.myapplication.keyboard.choose.databinding.ServiceDialogBinding; + + +public class ServiceDialog extends DialogFragment { + private ServiceDialogBinding serviceDialogBinding; + //private PermissionBtnListener permissionBtnListener; + private Context myContext; + private BroadcastReceiver broadcastReceiver; + + + public ServiceDialog(Context context) { + myContext = context; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + serviceDialogBinding = ServiceDialogBinding.inflate(inflater, null, false); + init(); + return serviceDialogBinding.getRoot(); + } + + /*public void setPermissionBtnListener(PermissionBtnListener permissionBtnListener) { + this.permissionBtnListener = permissionBtnListener; + }*/ + + + @Override + public void onResume() { + super.onResume(); + refreshBtnStatus(); + } + + public void refreshBtnStatus() { + boolean step1 = MyTools.FirstSetting(); + Log.d("----step1","----step"+step1); + boolean step2 = MyTools.SecondSetting(); + Log.d("----step2","----step"+step2); + serviceDialogBinding.mainDialogButton1.setSelected(step1); + serviceDialogBinding.mainDialogButton2.setSelected(step2); + } + + public void init() { + setCancelable(true); + Window window = getDialog().getWindow(); + window.setBackgroundDrawableResource(R.drawable.main_dialog_bg); + window.getDecorView().setPadding(0, 10, 0, 50); + WindowManager.LayoutParams wlp = window.getAttributes(); + wlp.gravity = Gravity.BOTTOM; + wlp.width = WindowManager.LayoutParams.MATCH_PARENT; + wlp.height = WindowManager.LayoutParams.WRAP_CONTENT; + window.setAttributes(wlp); + serviceDialogBinding.dialogFra.setVisibility(View.VISIBLE); + serviceDialogBinding.mainDialogButton1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MyTools.GotoFistSetting(myContext); + } + }); + serviceDialogBinding.mainDialogButton2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MyTools.GotoSecondSetting(); + } + }); + } +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/data/KeyBoardData.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/data/KeyBoardData.java new file mode 100644 index 0000000..8cac6bf --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/data/KeyBoardData.java @@ -0,0 +1,42 @@ +package com.kb.myapplication.keyboard.choose.data; + +import java.io.Serializable; + +public class KeyBoardData implements Serializable { + private String preview; + private String thumb; + private String title; + private String zipUrl; + + public String getPreview() { + return preview; + } + + public void setPreview(String preview) { + this.preview = preview; + } + + public String getThumb() { + return thumb; + } + + public void setThumb(String thumb) { + this.thumb = thumb; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getZipUrl() { + return zipUrl; + } + + public void setZipUrl(String zipUrl) { + this.zipUrl = zipUrl; + } +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/listener/DownloadZipListener.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/listener/DownloadZipListener.java new file mode 100644 index 0000000..e480b94 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/listener/DownloadZipListener.java @@ -0,0 +1,7 @@ +package com.kb.myapplication.keyboard.choose.listener; + +import java.io.File; + +public interface DownloadZipListener { + void downloadziplistener(boolean ok, File file); +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/listener/Downloadfilezip.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/listener/Downloadfilezip.java new file mode 100644 index 0000000..57ea77a --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/listener/Downloadfilezip.java @@ -0,0 +1,6 @@ +package com.kb.myapplication.keyboard.choose.listener; + + +public interface Downloadfilezip { + void downloadfilezip(boolean ok, String filepath); +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/room/LikeDataBase.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/room/LikeDataBase.java new file mode 100644 index 0000000..1ce48c2 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/room/LikeDataBase.java @@ -0,0 +1,19 @@ +package com.kb.myapplication.keyboard.choose.room; + +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; + +import com.kb.myapplication.keyboard.choose.value.MyValues; + +@Database(entities = {LikeDataEntity.class},version = 1,exportSchema = false) +public abstract class LikeDataBase extends RoomDatabase { + private static LikeDataBase likeDataBase; + public abstract LikeDataDAO getlikeDataDAO(); + public static synchronized LikeDataBase getLikeDataBase(){ + if(likeDataBase == null){ + likeDataBase = Room.databaseBuilder(MyValues.app, LikeDataBase.class,MyValues.DATABASE_NAME).build(); + } + return likeDataBase; + } +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/room/LikeDataDAO.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/room/LikeDataDAO.java new file mode 100644 index 0000000..cb14f4a --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/room/LikeDataDAO.java @@ -0,0 +1,27 @@ +package com.kb.myapplication.keyboard.choose.room; + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; +import androidx.room.Update; + +import java.util.List; +import java.util.Vector; + +@Dao +public interface LikeDataDAO { + @Query("select * from like_table where title=:title") + List QueryTitle(String title); + @Insert(onConflict = OnConflictStrategy.IGNORE) + void InsertLikeEntity(LikeDataEntity likeDataEntity); + @Delete + void DeleteLikeEntity(LikeDataEntity likeDataEntity); + @Update + void UpdateLikeEntity(LikeDataEntity likeDataEntity); + @Query("delete from like_table where title=:title") + void DeleteData(String title); + @Query("select * from like_table") + List GetAllData(); +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/room/LikeDataEntity.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/room/LikeDataEntity.java new file mode 100644 index 0000000..ae3201c --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/room/LikeDataEntity.java @@ -0,0 +1,59 @@ +package com.kb.myapplication.keyboard.choose.room; + +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; + +import com.kb.myapplication.keyboard.choose.value.MyValues; + +import java.io.Serializable; + +@Entity(tableName = MyValues.TABLE_NAME,indices = {@Index(value = "title",unique = true)}) +public class LikeDataEntity implements Serializable { + @PrimaryKey(autoGenerate = true) + private int keyboardid; + private String title; + private String preview; + private String thumb; + private String zipUrl; + + public int getKeyboardid() { + return keyboardid; + } + + public void setKeyboardid(int keyboardid) { + this.keyboardid = keyboardid; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getPreview() { + return preview; + } + + public void setPreview(String preview) { + this.preview = preview; + } + + public String getThumb() { + return thumb; + } + + public void setThumb(String thumb) { + this.thumb = thumb; + } + + public String getZipUrl() { + return zipUrl; + } + + public void setZipUrl(String zipUrl) { + this.zipUrl = zipUrl; + } +} diff --git a/app/src/main/java/com/kb/myapplication/keyboard/choose/value/MyValues.java b/app/src/main/java/com/kb/myapplication/keyboard/choose/value/MyValues.java new file mode 100644 index 0000000..e21c930 --- /dev/null +++ b/app/src/main/java/com/kb/myapplication/keyboard/choose/value/MyValues.java @@ -0,0 +1,15 @@ +package com.kb.myapplication.keyboard.choose.value; + +import com.kb.myapplication.keyboard.choose.LoveKeyBoard; + +public class MyValues { + public static final String TABLE_NAME = "like_table"; + public static final String DATABASE_NAME = "like_database"; + public static final String KeyBoard_name = "keyboard_name"; + public static final String KeyBoard_url = "keyboard_url"; + public static final String KeyBoard_pre = "keyboard_pre"; + public static final String KeyBoard_thumb = "keyboard_thumb"; + public static final int step1 = 1; + public static final int step2 = 2; + public static LoveKeyBoard app; +} diff --git a/app/src/main/res/drawable/back_image.xml b/app/src/main/res/drawable/back_image.xml new file mode 100644 index 0000000..51d5e62 --- /dev/null +++ b/app/src/main/res/drawable/back_image.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/btn_download_background.xml b/app/src/main/res/drawable/btn_download_background.xml new file mode 100644 index 0000000..b63635f --- /dev/null +++ b/app/src/main/res/drawable/btn_download_background.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/de_keybg.9.png b/app/src/main/res/drawable/de_keybg.9.png new file mode 100644 index 0000000..fcf5166 Binary files /dev/null and b/app/src/main/res/drawable/de_keybg.9.png differ diff --git a/app/src/main/res/drawable/de_keybg_press.9.png b/app/src/main/res/drawable/de_keybg_press.9.png new file mode 100644 index 0000000..b3f2727 Binary files /dev/null and b/app/src/main/res/drawable/de_keybg_press.9.png differ diff --git a/app/src/main/res/drawable/de_keyboard_bg.xml b/app/src/main/res/drawable/de_keyboard_bg.xml new file mode 100644 index 0000000..998644c --- /dev/null +++ b/app/src/main/res/drawable/de_keyboard_bg.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/del_icon.xml b/app/src/main/res/drawable/del_icon.xml new file mode 100644 index 0000000..1c653c8 --- /dev/null +++ b/app/src/main/res/drawable/del_icon.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/group.xml b/app/src/main/res/drawable/group.xml new file mode 100644 index 0000000..9d9de40 --- /dev/null +++ b/app/src/main/res/drawable/group.xml @@ -0,0 +1,23 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ico_shift_lit.xml b/app/src/main/res/drawable/ico_shift_lit.xml new file mode 100644 index 0000000..858c5ef --- /dev/null +++ b/app/src/main/res/drawable/ico_shift_lit.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/icon_back.xml b/app/src/main/res/drawable/icon_back.xml new file mode 100644 index 0000000..6f0920b --- /dev/null +++ b/app/src/main/res/drawable/icon_back.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/icon_download.xml b/app/src/main/res/drawable/icon_download.xml new file mode 100644 index 0000000..ec67a29 --- /dev/null +++ b/app/src/main/res/drawable/icon_download.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/key_image.xml b/app/src/main/res/drawable/key_image.xml new file mode 100644 index 0000000..22157ac --- /dev/null +++ b/app/src/main/res/drawable/key_image.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/like_image1.xml b/app/src/main/res/drawable/like_image1.xml new file mode 100644 index 0000000..e49f15f --- /dev/null +++ b/app/src/main/res/drawable/like_image1.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/like_image2.xml b/app/src/main/res/drawable/like_image2.xml new file mode 100644 index 0000000..2906d04 --- /dev/null +++ b/app/src/main/res/drawable/like_image2.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/main_bg2.xml b/app/src/main/res/drawable/main_bg2.xml new file mode 100644 index 0000000..ef76c3d --- /dev/null +++ b/app/src/main/res/drawable/main_bg2.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/main_dia_image.xml b/app/src/main/res/drawable/main_dia_image.xml new file mode 100644 index 0000000..d63186a --- /dev/null +++ b/app/src/main/res/drawable/main_dia_image.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/main_dialog_bg.xml b/app/src/main/res/drawable/main_dialog_bg.xml new file mode 100644 index 0000000..351f050 --- /dev/null +++ b/app/src/main/res/drawable/main_dialog_bg.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/main_dialog_button_bg.xml b/app/src/main/res/drawable/main_dialog_button_bg.xml new file mode 100644 index 0000000..253cefa --- /dev/null +++ b/app/src/main/res/drawable/main_dialog_button_bg.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/main_dialog_button_bg2.xml b/app/src/main/res/drawable/main_dialog_button_bg2.xml new file mode 100644 index 0000000..a116338 --- /dev/null +++ b/app/src/main/res/drawable/main_dialog_button_bg2.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/main_menu.xml b/app/src/main/res/drawable/main_menu.xml new file mode 100644 index 0000000..82af09a --- /dev/null +++ b/app/src/main/res/drawable/main_menu.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/menu.xml b/app/src/main/res/drawable/menu.xml new file mode 100644 index 0000000..29f8a7f --- /dev/null +++ b/app/src/main/res/drawable/menu.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/main/res/drawable/menu_bg.xml b/app/src/main/res/drawable/menu_bg.xml new file mode 100644 index 0000000..ee5c631 --- /dev/null +++ b/app/src/main/res/drawable/menu_bg.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/menu_like.xml b/app/src/main/res/drawable/menu_like.xml new file mode 100644 index 0000000..1731cca --- /dev/null +++ b/app/src/main/res/drawable/menu_like.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/menu_pracicy.xml b/app/src/main/res/drawable/menu_pracicy.xml new file mode 100644 index 0000000..11114e8 --- /dev/null +++ b/app/src/main/res/drawable/menu_pracicy.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/menu_set.xml b/app/src/main/res/drawable/menu_set.xml new file mode 100644 index 0000000..17d0b67 --- /dev/null +++ b/app/src/main/res/drawable/menu_set.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/menu_share.xml b/app/src/main/res/drawable/menu_share.xml new file mode 100644 index 0000000..ca2ee3d --- /dev/null +++ b/app/src/main/res/drawable/menu_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/pre_apply_bg.xml b/app/src/main/res/drawable/pre_apply_bg.xml new file mode 100644 index 0000000..53a17c0 --- /dev/null +++ b/app/src/main/res/drawable/pre_apply_bg.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_dialog_buttonbg.xml b/app/src/main/res/drawable/selector_dialog_buttonbg.xml new file mode 100644 index 0000000..22762ee --- /dev/null +++ b/app/src/main/res/drawable/selector_dialog_buttonbg.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/step_background.xml b/app/src/main/res/drawable/step_background.xml new file mode 100644 index 0000000..b63635f --- /dev/null +++ b/app/src/main/res/drawable/step_background.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/step_background_selected.xml b/app/src/main/res/drawable/step_background_selected.xml new file mode 100644 index 0000000..b63635f --- /dev/null +++ b/app/src/main/res/drawable/step_background_selected.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/step_selector.xml b/app/src/main/res/drawable/step_selector.xml new file mode 100644 index 0000000..49be956 --- /dev/null +++ b/app/src/main/res/drawable/step_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tablelayout_bg.xml b/app/src/main/res/drawable/tablelayout_bg.xml new file mode 100644 index 0000000..da9ef45 --- /dev/null +++ b/app/src/main/res/drawable/tablelayout_bg.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/thumb_bg.xml b/app/src/main/res/drawable/thumb_bg.xml new file mode 100644 index 0000000..c884b6d --- /dev/null +++ b/app/src/main/res/drawable/thumb_bg.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_favourite.xml b/app/src/main/res/layout/activity_favourite.xml new file mode 100644 index 0000000..d31309e --- /dev/null +++ b/app/src/main/res/layout/activity_favourite.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_into.xml b/app/src/main/res/layout/activity_into.xml new file mode 100644 index 0000000..dd62ba2 --- /dev/null +++ b/app/src/main/res/layout/activity_into.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_list_all_data.xml b/app/src/main/res/layout/activity_list_all_data.xml new file mode 100644 index 0000000..fbe162b --- /dev/null +++ b/app/src/main/res/layout/activity_list_all_data.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..4feee14 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_pre_view.xml b/app/src/main/res/layout/activity_pre_view.xml new file mode 100644 index 0000000..86aff8b --- /dev/null +++ b/app/src/main/res/layout/activity_pre_view.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_setting.xml b/app/src/main/res/layout/activity_setting.xml new file mode 100644 index 0000000..afbe97b --- /dev/null +++ b/app/src/main/res/layout/activity_setting.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fav_recycle.xml b/app/src/main/res/layout/fav_recycle.xml new file mode 100644 index 0000000..d4c2648 --- /dev/null +++ b/app/src/main/res/layout/fav_recycle.xml @@ -0,0 +1,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/keyboard_thumb.xml b/app/src/main/res/layout/keyboard_thumb.xml new file mode 100644 index 0000000..fc6f940 --- /dev/null +++ b/app/src/main/res/layout/keyboard_thumb.xml @@ -0,0 +1,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/mian_recycle.xml b/app/src/main/res/layout/mian_recycle.xml new file mode 100644 index 0000000..913a975 --- /dev/null +++ b/app/src/main/res/layout/mian_recycle.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/app/src/main/res/layout/my_input_view.xml b/app/src/main/res/layout/my_input_view.xml new file mode 100644 index 0000000..39cb8b9 --- /dev/null +++ b/app/src/main/res/layout/my_input_view.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/service_dialog.xml b/app/src/main/res/layout/service_dialog.xml new file mode 100644 index 0000000..2c2a459 --- /dev/null +++ b/app/src/main/res/layout/service_dialog.xml @@ -0,0 +1,51 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu.xml b/app/src/main/res/menu/menu.xml new file mode 100644 index 0000000..49c5cea --- /dev/null +++ b/app/src/main/res/menu/menu.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/favouritenull_bg.png b/app/src/main/res/mipmap-hdpi/favouritenull_bg.png new file mode 100644 index 0000000..814ddde Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/favouritenull_bg.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-hdpi/icon_logo.png b/app/src/main/res/mipmap-hdpi/icon_logo.png new file mode 100644 index 0000000..5fcea86 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/icon_logo.png differ diff --git a/app/src/main/res/mipmap-hdpi/into_image.png b/app/src/main/res/mipmap-hdpi/into_image.png new file mode 100644 index 0000000..74fb610 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/into_image.png differ diff --git a/app/src/main/res/mipmap-hdpi/logo.png b/app/src/main/res/mipmap-hdpi/logo.png new file mode 100644 index 0000000..4fc5d94 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/logo.png differ diff --git a/app/src/main/res/mipmap-hdpi/main_bg.png b/app/src/main/res/mipmap-hdpi/main_bg.png new file mode 100644 index 0000000..6e9b758 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/main_bg.png differ diff --git a/app/src/main/res/mipmap-hdpi/main_bg2.png b/app/src/main/res/mipmap-hdpi/main_bg2.png new file mode 100644 index 0000000..cfeab65 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/main_bg2.png differ diff --git a/app/src/main/res/mipmap-hdpi/main_image.png b/app/src/main/res/mipmap-hdpi/main_image.png new file mode 100644 index 0000000..67e32b9 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/main_image.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..c1e8989 --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..dcfc531 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #FF000000 + #FFFFFFFF + #022C42 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..e955f9e --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,27 @@ + + Love Keyboard + Like + Main + keyboard wallpaper + 134 species + Welcome to the keyboard wallpaper + + Hello blank fragment + keyboard wallpaper + Apply + Go to add + Unlock More Features with Keyboard! + Step 1:Select + Step 2:Enabled + Favorites + Settings + Share + Privacy policy + Favorites + Successfully!Added to likes + Favorites is empty + + Apply the keyboard skin successfully + waitting + https://play.google.com/store/apps/details?id=com.kb.myapplication.keyboard.choose + \ No newline at end of file diff --git a/app/src/main/res/values/style.xml b/app/src/main/res/values/style.xml new file mode 100644 index 0000000..dbbad75 --- /dev/null +++ b/app/src/main/res/values/style.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..e52df44 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..fa0f996 --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/board_view_one.xml b/app/src/main/res/xml/board_view_one.xml new file mode 100644 index 0000000..42868c9 --- /dev/null +++ b/app/src/main/res/xml/board_view_one.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/board_view_three.xml b/app/src/main/res/xml/board_view_three.xml new file mode 100644 index 0000000..86d6441 --- /dev/null +++ b/app/src/main/res/xml/board_view_three.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/board_view_two.xml b/app/src/main/res/xml/board_view_two.xml new file mode 100644 index 0000000..e2484e3 --- /dev/null +++ b/app/src/main/res/xml/board_view_two.xml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/filepaths.xml b/app/src/main/res/xml/filepaths.xml new file mode 100644 index 0000000..bb368b0 --- /dev/null +++ b/app/src/main/res/xml/filepaths.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/xml/im.xml b/app/src/main/res/xml/im.xml new file mode 100644 index 0000000..aeaa192 --- /dev/null +++ b/app/src/main/res/xml/im.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/test/java/com/kb/myapplication/keyboard/choose/ExampleUnitTest.java b/app/src/test/java/com/kb/myapplication/keyboard/choose/ExampleUnitTest.java new file mode 100644 index 0000000..d80cf74 --- /dev/null +++ b/app/src/test/java/com/kb/myapplication/keyboard/choose/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package com.kb.myapplication.keyboard.choose; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..a04e5ba --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,5 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false + id("org.jetbrains.kotlin.android") version "1.9.0" apply false +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..00d252e --- /dev/null +++ b/gradle.properties @@ -0,0 +1,22 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true +android.nonFinalResIds=false \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..7d802a8 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,22 @@ +[versions] +agp = "8.1.3" +junit = "4.13.2" +junitVersion = "1.2.1" +espressoCore = "3.6.1" +appcompat = "1.7.0" +material = "1.12.0" +activity = "1.9.0" +constraintlayout = "2.1.4" + +[libraries] +junit = { group = "junit", name = "junit", version.ref = "junit" } +ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } +activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } +constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..a0a2252 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Jul 15 15:51:20 CST 2024 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..1e661c0 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + maven("https://jitpack.io") + } +} + +rootProject.name = "LoveKeyBoard" +include(":app") + \ No newline at end of file