V1.0.1(2) Ad版本

This commit is contained in:
litingting 2024-04-16 18:09:49 +08:00
commit fc69284365
80 changed files with 6779 additions and 0 deletions

18
.gitignore vendored Normal file
View File

@ -0,0 +1,18 @@
*.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
.idea/
.safedk/
app/release/

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

3
app/SignInfo Normal file
View File

@ -0,0 +1,3 @@
签名文件:keyboardSkinning.jks
别名:keyboardSkinningkey0
密码:keyboardSkinning

79
app/build.gradle.kts Normal file
View File

@ -0,0 +1,79 @@
import java.util.Date
import java.text.SimpleDateFormat
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("applovin-quality-service")
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
}
applovin{
apiKey = "y87o4e7vb5bbqzuGVTFyOIfZiyBG0Nf0Ksq8S3m2MJOHf_A5BcWGJnKuQqoxwxVvtdQdiTC4O3MPzFwy8rJ9Cc"
}
val timestamp = SimpleDateFormat("MM_dd_HH_mm").format(Date())
android {
namespace = "com.keyboardskinning.theme"
compileSdk = 34
defaultConfig {
applicationId = "com.keyboardskinning.theme"
minSdk = 23
targetSdk = 34
versionCode = 2
versionName = "1.0.1"
setProperty("archivesBaseName", "KeyboardSkinning_V" + versionName + "(${versionCode})_$timestamp")
testInstrumentationRunner = "androidx.theme.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.activity:activity-compose:1.8.2")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation ("com.github.bumptech.glide:glide:4.16.0")
implementation("com.github.omicronapps:7-Zip-JBinding-4Android:Release-16.02-2.02")
implementation("com.applovin:applovin-sdk:+")
implementation("com.applovin.mediation:vungle-adapter:+")
implementation("com.applovin.mediation:bytedance-adapter:+")
implementation(platform("com.google.firebase:firebase-bom:32.3.1"))
implementation("com.google.firebase:firebase-analytics-ktx")
implementation ("com.google.firebase:firebase-crashlytics-ktx")
}

29
app/google-services.json Normal file
View File

@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "385313805976",
"project_id": "keyboardskinning",
"storage_bucket": "keyboardskinning.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:385313805976:android:9e3927a4b6f971fd4ce2ed",
"android_client_info": {
"package_name": "com.keyboardskinning.theme"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyBNx_DWofqkP9FDOyZ2UjK7ryHfLPcD9OU"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

BIN
app/keyboardSkinning.jks Normal file

Binary file not shown.

23
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,23 @@
# 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 SourceFile
-keep class com.omicronapplications.** { *; }
-keep class net.sf.sevenzipjbinding.** { *; }

View File

@ -0,0 +1,24 @@
package com.keyboardskinning.theme
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented theme, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under theme.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.keyboardskinning.theme", appContext.packageName)
}
}

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".KeyboardSkin"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/icon2"
android:label="@string/app_name"
android:largeHeap="true"
android:roundIcon="@mipmap/icon2"
android:supportsRtl="true"
android:theme="@style/Theme.KeyboardSkinning"
tools:targetApi="31">
<activity
android:name=".ui.ActivityHome"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".tools.MyService"
android:exported="true"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data
android:name="android.view.im"
android:resource="@xml/im" />
</service>
<activity
android:name=".ui.MainActivity"
android:exported="false">
</activity>
<activity
android:name=".ui.PreviewActivity"
android:exported="false" />
<activity
android:name=".ui.SettingActivity"
android:exported="false" />
<meta-data
android:name="applovin.sdk.key"
android:value="3cUMfTcsZKzlJevxK4IkNysgDAeQA4B5w332p3g8B9ZAgC54WQNZLVxuxnCx4sCHA5StLJnDTAFa68mFTi8rd8" />
</application>
</manifest>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
package com.keyboardskinning.theme;
import android.app.Application;
import com.applovin.mediation.ads.MaxInterstitialAd;
import com.applovin.sdk.AppLovinSdk;
import com.applovin.sdk.AppLovinSdkConfiguration;
import com.keyboardskinning.theme.tools.MyTools;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class KeyboardSkin extends Application {
public static KeyboardSkin app;
public static List<MyData> myDataArrayList = new ArrayList<>();
private boolean isInit = false;
@Override
public void onCreate() {
super.onCreate();
app = this;
List<MyData> myData = MyTools.parseJson(this);
if(myData != null){
myDataArrayList = myData;
}
}
public static List<MyData> getMyDataArrayList() {
Collections.shuffle(myDataArrayList);
return myDataArrayList;
}
}

View File

@ -0,0 +1,42 @@
package com.keyboardskinning.theme;
public class MyData {
private String resourceName;
private String thumbnail;
private String preview;
private String url;
public void setPreview(String preview) {
this.preview = preview;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
public void setThumbnail(String thumbnail) {
this.thumbnail = thumbnail;
}
public void setUrl(String url) {
this.url = url;
}
public String getPreview() {
return preview;
}
public String getResourceName() {
return resourceName;
}
public String getThumbnail() {
return thumbnail;
}
public String getUrl() {
return url;
}
}

View File

@ -0,0 +1,82 @@
package com.keyboardskinning.theme.mylistadapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.keyboardskinning.theme.MyData;
import com.keyboardskinning.theme.R;
import com.keyboardskinning.theme.ui.PreviewActivity;
import java.util.List;
public class ThumbAdapter extends RecyclerView.Adapter<ThumbAdapter.ThumbViewHolder> {
private Context adapter_Context;
private List<MyData> myDataList;
public ThumbAdapter(Context context,List<MyData> list){
adapter_Context = context;
myDataList = list;
}
@Override
public void onBindViewHolder(@NonNull ThumbViewHolder holder, int position) {
MyData myData = myDataList.get(position);
String thumbnail = myData.getThumbnail();
Glide.with(adapter_Context).load(thumbnail).into(holder.getImageViewThumb());
holder.getConstraintLayout().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(adapter_Context, PreviewActivity.class);
intent.putExtra(PreviewActivity.KEY_NAME,myData.getResourceName());
intent.putExtra(PreviewActivity.KEY_URL,myData.getUrl());
intent.putExtra(PreviewActivity.KEY_PRE,myData.getPreview());
adapter_Context.startActivity(intent);
}
});
}
public static final class ThumbViewHolder extends RecyclerView.ViewHolder{
private ImageView imageViewThumb;
private ConstraintLayout constraintLayout;
public ThumbViewHolder(@NonNull View itemView) {
super(itemView);
imageViewThumb = itemView.findViewById(R.id.image_view_thumb_id);
constraintLayout = itemView.findViewById(R.id.constraint_layout_id);
}
public ConstraintLayout getConstraintLayout() {
return constraintLayout;
}
public ImageView getImageViewThumb() {
return imageViewThumb;
}
}
@Override
public int getItemCount() {
return myDataList.size();
}
@NonNull
@Override
public ThumbViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(adapter_Context).inflate(R.layout.list_thumb, parent, false);
ThumbViewHolder thumbViewHolder = new ThumbViewHolder(itemView);
return thumbViewHolder;
}
}

View File

@ -0,0 +1,13 @@
package com.keyboardskinning.theme.mylistener;
import com.applovin.mediation.MaxAd;
import com.applovin.mediation.MaxError;
public interface AdCallback {
void onShowFail(MaxAd ad);
void onShowSuccess(MaxAd ad);
void onHidden( );
void onLoadFail(String string, MaxError maxError);
void onLoadSuccess(MaxAd ad);
}

View File

@ -0,0 +1,8 @@
package com.keyboardskinning.theme.mylistener;
import java.io.File;
public interface DownloadCallback {
void onDownloadCall(boolean successful, File resource);
}

View File

@ -0,0 +1,6 @@
package com.keyboardskinning.theme.mylistener;
public interface UnzipCallback {
void onUnzipCall(boolean successful, String resDirPath);
}

View File

@ -0,0 +1,128 @@
package com.keyboardskinning.theme.tools;
import android.app.Activity;
import android.util.Log;
import androidx.annotation.NonNull;
import com.applovin.mediation.MaxAd;
import com.applovin.mediation.MaxAdListener;
import com.applovin.mediation.MaxError;
import com.applovin.mediation.ads.MaxInterstitialAd;
import com.keyboardskinning.theme.mylistener.AdCallback;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Admanager {
public static final String unit1 = "aa5f1b6007e164bb";
public static final String unit2 = "2508a453b5762c26";
public static final String unit3 = "15208b32ede43744";
public static MaxInterstitialAd show(List<MaxInterstitialAd> ads) {
Collections.shuffle(ads);
for (int g = 0; g < ads.size(); g++) {
MaxInterstitialAd maxInterstitialAd = ads.get(g);
if (maxInterstitialAd.isReady()) {
return maxInterstitialAd;
}
}
return null;
}
public static void setAdShowCall(MaxInterstitialAd ad, AdCallback adListener) {
ad.setListener(new MaxAdListener() {
@Override
public void onAdLoaded(@NonNull MaxAd maxAd) {
if (adListener != null) {
adListener.onLoadSuccess(maxAd);
}
}
@Override
public void onAdDisplayed(@NonNull MaxAd maxAd) {
if (adListener != null) {
adListener.onShowSuccess(maxAd);
}
}
@Override
public void onAdHidden(@NonNull MaxAd maxAd) {
if (adListener != null) {
adListener.onHidden();
}
}
@Override
public void onAdClicked(@NonNull MaxAd maxAd) {
}
@Override
public void onAdLoadFailed(@NonNull String s, @NonNull MaxError maxError) {
if (adListener != null) {
adListener.onLoadFail(s, maxError);
}
}
@Override
public void onAdDisplayFailed(@NonNull MaxAd maxAd, @NonNull MaxError maxError) {
if (adListener != null) {
adListener.onShowFail(maxAd);
}
}
});
}
public static List<MaxInterstitialAd> initMyAd(Activity mActivity) {
MaxInterstitialAd ad1 = new MaxInterstitialAd(unit1, mActivity);
ad1.setListener(new MaxAdListener() {
@Override
public void onAdLoaded(@NonNull MaxAd maxAd) {
Log.d("-------","--------onAdLoaded ad1"+ad1.getAdUnitId());
}
@Override
public void onAdDisplayed(@NonNull MaxAd maxAd) {
}
@Override
public void onAdHidden(@NonNull MaxAd maxAd) {
}
@Override
public void onAdClicked(@NonNull MaxAd maxAd) {
}
@Override
public void onAdLoadFailed(@NonNull String s, @NonNull MaxError maxError) {
Log.d("-------","--------onAdLoadFailed ad1"+ad1.getAdUnitId());
}
@Override
public void onAdDisplayFailed(@NonNull MaxAd maxAd, @NonNull MaxError maxError) {
}
});
ad1.loadAd();
MaxInterstitialAd ad2 = new MaxInterstitialAd(unit2, mActivity);
ad2.loadAd();
MaxInterstitialAd ad3 = new MaxInterstitialAd(unit3, mActivity);
ad3.loadAd();
ArrayList<MaxInterstitialAd> ads = new ArrayList<>();
ads.add(ad1);
ads.add(ad2);
ads.add(ad3);
return ads;
}
}

View File

@ -0,0 +1,200 @@
package com.keyboardskinning.theme.tools;
import android.content.Context;
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.keyboardskinning.theme.KeyboardSkin;
import com.keyboardskinning.theme.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(KeyboardSkin.app, R.drawable.ico_shift_lit);
private Drawable iconDel = ContextCompat.getDrawable(KeyboardSkin.app, R.drawable.del_icon);
private Drawable BG = ContextCompat.getDrawable(KeyboardSkin.app, R.drawable.de_keyboard_bg);
private int keyNoramlcolor = KeyboardSkin.app.getResources().getColor(R.color.white, null);
private int keyActioncolor = KeyboardSkin.app.getResources().getColor(R.color.white, null);
private Drawable iconShiftLock = ContextCompat.getDrawable(KeyboardSkin.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(KeyboardSkin.app, R.drawable.ico_shift_lit);
iconDel = ContextCompat.getDrawable(KeyboardSkin.app, R.drawable.del_icon);
BG = ContextCompat.getDrawable(KeyboardSkin.app, R.drawable.de_keyboard_bg);
keyNoramlcolor = KeyboardSkin.app.getResources().getColor(R.color.white, null);
iconShiftLock = ContextCompat.getDrawable(KeyboardSkin.app, R.drawable.ico_shift_lit);
Drawable drawable1 = ContextCompat.getDrawable(
KeyboardSkin.app,
R.drawable.de_keybg_press
);
Drawable drawable = ContextCompat.getDrawable(KeyboardSkin.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;
}
BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), BitmapFactory.decodeFile(filePath));
return bitmapDrawable;
}
private Drawable getBackGround(Context context,String resDirPath)
{
String filePath = resDirPath+path_drawxxh+jpg_BG;
if (!new File(filePath).exists()) {
return null;
}
BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), BitmapFactory.decodeFile(filePath));
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.getSkin();
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);
}
}

View File

@ -0,0 +1,53 @@
package com.keyboardskinning.theme.tools
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:MyKeyBoardView
){
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)
}
}
}
}

View File

@ -0,0 +1,849 @@
package com.keyboardskinning.theme.tools;
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.keyboardskinning.theme.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<Key> mKeys;
/** List of modifier keys such as Shift & Alt, if any */
private List<Key> 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<Row> 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<Key> 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.
*
* <p>Toggled state of the key will be flipped when all the following conditions are
* fulfilled:</p>
*
* <ul>
* <li>This is a sticky key, that is, {@link #sticky} is {@code true}.
* <li>The parameter {@code inside} is {@code true}.
* <li>{@link android.os.Build.VERSION#SDK_INT} is greater than
* {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
* </ul>
*
* @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<Key> getKeys() {
return mKeys;
}
public List<Key> 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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,157 @@
package com.keyboardskinning.theme.tools;
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 java.util.List;
public class MyKeyBoardView extends KeyBoardView {
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 MyKeyBoardView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MyKeyBoardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
public MyKeyBoardView(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<KeyBoard.Key> 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);
}
}
}

View File

@ -0,0 +1,183 @@
package com.keyboardskinning.theme.tools;
import android.annotation.SuppressLint;
import android.inputmethodservice.InputMethodService;
import android.os.SystemClock;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import com.keyboardskinning.theme.R;
import java.util.List;
public class MyService extends InputMethodService implements KeyBoardView.OnKeyboardActionListener {
private long last_click = -1L;
private int[] ViewXmls = new int[3];
private boolean is_double = false;
private MyKeyBoardView myKeyBoardView;
@SuppressLint("MissingInflatedId")
@Override
public View onCreateInputView() {
ViewXmls[0] = R.xml.view_1;
ViewXmls[1] = R.xml.view_2;
ViewXmls[2] = R.xml.view_3;
View inputView = LayoutInflater.from(this).inflate(R.layout.customer_input_view, null, false);
myKeyBoardView = (MyKeyBoardView) inputView.findViewById(R.id.my_keyboard_view);
myKeyBoardView.setPreviewEnabled(false);
myKeyBoardView.setKeyboard(new KeyBoard(this, ViewXmls[0]));
myKeyBoardView.setOnKeyboardActionListener(this);
return inputView;
}
@Override
public void onWindowShown() {
super.onWindowShown();
myKeyBoardView.updateConfigView(this);
}
@Override
public void onPress(int primaryCode) {
if (primaryCode == KeyBoard.KEYCODE_SHIFT) {
if (300 > SystemClock.elapsedRealtime() - last_click) {
is_double = true;
}
last_click = SystemClock.elapsedRealtime();
}
}
@Override
public void onRelease(int primaryCode) {
}
private void switchCapital(Boolean toCapital, KeyBoard keyboard) {
List<KeyBoard.Key> keys = keyboard.getKeys();
for(int h = 0;h<keys.size();h++){
KeyBoard.Key key = keys.get(h);
if(key.label != null && key.label != ""){
if(key.label.length() == 1){
String s = key.label.toString();
char myChar;
if(toCapital){
myChar = s.toUpperCase().charAt(0);
}else {
myChar = s.toLowerCase().charAt(0);
}
key.label = String.valueOf(myChar);
key.codes[0] = (int) myChar;
}
}
}
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
switch (primaryCode) {
case KeyBoard.KEYCODE_SHIFT:
int shiftStatus = myKeyBoardView.getShift_status();
KeyBoard keyboard = myKeyBoardView.getKeyboard();
switch (shiftStatus){
case 0:
if(is_double){
myKeyBoardView.setShift_status(2);
}else {
myKeyBoardView.setShift_status(1);
}
switchCapital(true,keyboard);
myKeyBoardView.setKeyboard(keyboard);
break;
case 1:
if(is_double){
myKeyBoardView.setShift_status(2);
}else {
switchCapital(false,keyboard);
myKeyBoardView.setShift_status(0);
}
myKeyBoardView.setKeyboard(keyboard);
break;
case 2:
myKeyBoardView.setShift_status(0);
switchCapital(false,keyboard);
myKeyBoardView.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_DONE);
break;
case KeyBoard.KEYCODE_MODE_CHANGE:
if(myKeyBoardView.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 = myKeyBoardView.getShift_status();
KeyBoard keyboard1 = myKeyBoardView.getKeyboard();
if(shiftStatus2 == 1){
myKeyBoardView.setShift_status(0);
switchCapital(false,keyboard1);
myKeyBoardView.setKeyboard(keyboard1);
}
break;
}
}
private void changeView(int type) {
myKeyBoardView.setViewType(type);
myKeyBoardView.setKeyboard(new KeyBoard(this, ViewXmls[type]));
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeDown() {
}
@Override
public void swipeUp() {
}
}

View File

@ -0,0 +1,270 @@
package com.keyboardskinning.theme.tools;
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 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.keyboardskinning.theme.KeyboardSkin;
import com.keyboardskinning.theme.MyData;
import com.keyboardskinning.theme.mylistener.DownloadCallback;
import com.keyboardskinning.theme.mylistener.UnzipCallback;
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;
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;
public class MyTools {
private static String sharedpreferenceName = "share_name";
private static String sharedpreferenceKey_skin = "key_skin";
private static final SharedPreferences share = KeyboardSkin.app.getSharedPreferences(
sharedpreferenceName,
Context.MODE_PRIVATE
);
public static StateListDrawable getStatus(Drawable draw, Drawable drawPress) {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[android.R.attr.state_pressed], draw);
stateListDrawable.addState(new int[0], drawPress);
return stateListDrawable;
}
public static float spToPpx(Float values, Context context) {
float scale = context.getResources().getDisplayMetrics().scaledDensity;
return values * scale;
}
private static final SharedPreferences.Editor editorShare = share.edit();
private static InputMethodManager methodManager = (InputMethodManager) KeyboardSkin.app.getSystemService(Context.INPUT_METHOD_SERVICE);
public static List<MyData> parseJson(Context context) {
StringBuilder sb = new StringBuilder();
try {
InputStream open = context.getAssets().open("selecion.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;
}
}
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 saveSkin(String resDirPath) {
editorShare.putString(sharedpreferenceKey_skin, resDirPath);
editorShare.apply();
}
public static String getSkin() {
return share.getString(sharedpreferenceKey_skin, "");
}
public static String getSkinPathByName(String name) {
return share.getString(name, "");
}
public static void saveSkinByName(String name, String resDirPath) {
editorShare.putString(name, resDirPath);
editorShare.apply();
}
public static int dpToPx(int dp, Context context) {
float density = context.getResources().getDisplayMetrics().density;
return (int) (dp * density);
}
private static List<MyData> parseJsonString(String jsonString) {
List<MyData> myDataArrayList = new ArrayList<>();
try {
JSONObject string1 = new JSONObject(jsonString);
JSONArray list = string1.getJSONArray("list");
for (int g = 0; g < list.length(); g++) {
MyData myData = new MyData();
JSONObject item = list.getJSONObject(g);
String preview = item.getString("preview");
String thumb = item.getString("thumb");
String title = item.getString("title");
String zipUrl = item.getString("zipUrl");
myData.setPreview(String.valueOf(preview));
myData.setThumbnail(thumb);
myData.setUrl(zipUrl);
myData.setResourceName(title);
myDataArrayList.add(myData);
}
return myDataArrayList;
} catch (JSONException jsonException) {
return null;
}
}
public static void goSetStep2() {
methodManager.showInputMethodPicker();
}
public static boolean isStep2() {
String string = Settings.Secure.getString(KeyboardSkin.app.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
if (string.startsWith(KeyboardSkin.app.getPackageName())) {
return true;
} else {
return false;
}
}
public static void goSetStep1(Context context) {
Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
context.startActivity(intent);
}
public static boolean isStep1() {
for (InputMethodInfo inputMethodInfo : methodManager.getEnabledInputMethodList()) {
if (inputMethodInfo.getId().startsWith(KeyboardSkin.app.getPackageName())) {
return true;
}
}
return false;
}
public static void downloadZip(String url, Context context, DownloadCallback callback) {
Glide.with(context)
.asFile()
.load(url)
.addListener(new RequestListener<File>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<File> target, boolean isFirstResource) {
callback.onDownloadCall(false, null);
return false;
}
@Override
public boolean onResourceReady(@NonNull File resource, @NonNull Object model, Target<File> target, @NonNull DataSource dataSource, boolean isFirstResource) {
callback.onDownloadCall(true, resource);
return false;
}
}
).preload();
}
public static void unzipFile(
String unzipPath,
File resource,
UnzipCallback unzipCallback
) {
if (!resource.exists()) {
unzipCallback.onUnzipCall(false, "");
return;
}
String itemFilePath = "";
RandomAccessFileOutStream outStream = 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(unzipPath, simple.getPath());
if (!simple.isFolder()) {
outStream = new RandomAccessFileOutStream(new RandomAccessFile(file, "rw"));
simple.extractSlow(outStream);
itemFilePath = file.getPath();
} else {
boolean mkdirs = file.mkdirs();
}
}
randomAccessFileInStream.close();
openInArchive.close();
if (outStream != null) {
outStream.close();
}
int res = itemFilePath.indexOf("res");
String substring = itemFilePath.substring(0, res + 3);
unzipCallback.onUnzipCall(true, substring);
} catch (FileNotFoundException | SevenZipException e) {
unzipCallback.onUnzipCall(false, "");
} catch (IOException e) {
unzipCallback.onUnzipCall(false, "");
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,56 @@
package com.keyboardskinning.theme.tools;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class SpaceItem 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 SpaceItem(int v_space, int h_space, int ex_space) {
this.ex_space = ex_space;
this.h_space = h_space;
this.v_space = v_space;
}
}

View File

@ -0,0 +1,117 @@
package com.keyboardskinning.theme.ui;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.util.Log;
import com.applovin.mediation.MaxAd;
import com.applovin.mediation.MaxError;
import com.applovin.mediation.ads.MaxInterstitialAd;
import com.applovin.sdk.AppLovinSdk;
import com.applovin.sdk.AppLovinSdkConfiguration;
import com.keyboardskinning.theme.R;
import com.keyboardskinning.theme.mylistener.AdCallback;
import com.keyboardskinning.theme.tools.Admanager;
import java.util.List;
public class ActivityHome extends AppCompatActivity implements AdCallback {
private boolean needShow = true;
private List<MaxInterstitialAd> maxInterstitialAds;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initSDK();
setContentView(R.layout.activity_home);
}
private void initSDK() {
AppLovinSdk.getInstance(this).setMediationProvider("max");
AppLovinSdk.getInstance(this).initializeSdk(new AppLovinSdk.SdkInitializationListener() {
@Override
public void onSdkInitialized(AppLovinSdkConfiguration appLovinSdkConfiguration) {
maxInterstitialAds = Admanager.initMyAd(ActivityHome.this);
Log.d("-------","--------init");
go();
}
});
}
private void go() {
CountDownTimer countDownTimer = new CountDownTimer(13000, 500) {
@Override
public void onTick(long millisUntilFinished) {
if (needShow) {
MaxInterstitialAd cacheAd = Admanager.show(maxInterstitialAds);
if (cacheAd != null) {
Log.d("-------","--------showAd0");
showAd(cacheAd);
}
}
}
@Override
public void onFinish() {
if (needShow) {
MaxInterstitialAd cacheAd = Admanager.show(maxInterstitialAds);
if (cacheAd != null) {
Log.d("-------","--------showAd1");
showAd(cacheAd);
} else {
Log.d("-------","--------enterMain0");
enterMain();
}
}
}
};
countDownTimer.start();
}
private void showAd(MaxInterstitialAd cacheAd) {
needShow = false;
Admanager.setAdShowCall(cacheAd, ActivityHome.this);
cacheAd.showAd();
}
@Override
public void onShowFail(MaxAd ad) {
Log.d("-------","--------onShowFail");
enterMain();
}
@Override
public void onShowSuccess(MaxAd ad) {
}
@Override
public void onHidden() {
Log.d("-------","--------onHidden");
enterMain();
}
@Override
public void onLoadFail(String string, MaxError maxError) {
}
@Override
public void onLoadSuccess(MaxAd ad) {
}
private void enterMain() {
Intent intent = new Intent(ActivityHome.this, MainActivity.class);
startActivity(intent);
finish();
}
}

View File

@ -0,0 +1,33 @@
package com.keyboardskinning.theme.ui;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import com.keyboardskinning.theme.KeyboardSkin;
import com.keyboardskinning.theme.R;
import com.keyboardskinning.theme.mylistadapter.ThumbAdapter;
import com.keyboardskinning.theme.tools.MyTools;
import com.keyboardskinning.theme.tools.SpaceItem;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
recyclerView.setAdapter(new ThumbAdapter(this, KeyboardSkin.getMyDataArrayList()));
recyclerView.setLayoutManager(new GridLayoutManager(this,2));
recyclerView.addItemDecoration(new SpaceItem(MyTools.dpToPx(10,this),MyTools.dpToPx(10,this),MyTools.dpToPx(10,this)));
}
private void initView(){
recyclerView = findViewById(R.id.recycler_view_id);
}
}

View File

@ -0,0 +1,236 @@
package com.keyboardskinning.theme.ui;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.applovin.mediation.MaxAd;
import com.applovin.mediation.MaxError;
import com.applovin.mediation.ads.MaxInterstitialAd;
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.keyboardskinning.theme.R;
import com.keyboardskinning.theme.mylistener.AdCallback;
import com.keyboardskinning.theme.mylistener.DownloadCallback;
import com.keyboardskinning.theme.mylistener.UnzipCallback;
import com.keyboardskinning.theme.tools.Admanager;
import com.keyboardskinning.theme.tools.MyTools;
import java.io.File;
import java.util.List;
public class PreviewActivity extends AppCompatActivity {
private String url;
private String name;
private String preview;
private ImageView imageViewBack;
private ImageView imageViewPreviwew;
private TextView textViewName;
private LinearLayout linearLayoutDownload;
public static String KEY_NAME = "key_name";
public static String KEY_URL = "key_url";
public static String KEY_PRE = "key_pre";
private String unzipPath;
private ProgressBar progressBarPreview;
private ProgressBar progressBarDownload;
private List<MaxInterstitialAd> maxInterstitialAds;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
maxInterstitialAds = Admanager.initMyAd(PreviewActivity.this);
setContentView(R.layout.activity_preview);
initView();
progressBarPreview.setVisibility(View.VISIBLE);
onGetData();
}
private void initView() {
imageViewBack = findViewById(R.id.image_view_back_id);
imageViewPreviwew = findViewById(R.id.image_view_preview_id);
textViewName = findViewById(R.id.text_view_name_id);
linearLayoutDownload = findViewById(R.id.linear_layout_download_id);
progressBarPreview = findViewById(R.id.progress_bar_preview_id);
progressBarDownload = findViewById(R.id.progress_bar_download_id);
}
public void onGetData() {
Intent intent = getIntent();
name = intent.getStringExtra(KEY_NAME);
preview = intent.getStringExtra(KEY_PRE);
url = intent.getStringExtra(KEY_URL);
textViewName.setText(name);
Glide.with(this).load(preview).addListener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
progressBarPreview.setVisibility(View.GONE);
return false;
}
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
progressBarPreview.setVisibility(View.GONE);
return false;
}
}).into(imageViewPreviwew);
File cacheDir = this.getCacheDir();
unzipPath = cacheDir + "/" + name;
setListener();
}
private void setListener() {
linearLayoutDownload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setAction();
}
});
imageViewBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("-------","--------finish ");
showBackAd();
finish();
}
});
}
@Override
public void onBackPressed() {
super.onBackPressed();
Log.d("-------","--------onBackPressed ");
showBackAd();
}
private void showBackAd(){
MaxInterstitialAd cacheAd = Admanager.show(maxInterstitialAds);
if(cacheAd != null){
cacheAd.showAd();
}
}
private void setAction() {
if (!MyTools.isStep1() || !MyTools.isStep2()) {
Toast.makeText(this, getString(R.string.text_hint), Toast.LENGTH_SHORT).show();
Intent intent = new Intent(this, SettingActivity.class);
startActivity(intent);
return;
}
MaxInterstitialAd cacheAd = Admanager.show(maxInterstitialAds);
if (cacheAd != null) {
Admanager.setAdShowCall(cacheAd, new AdCallback() {
@Override
public void onShowFail(MaxAd ad) {
goApply();
}
@Override
public void onShowSuccess(MaxAd ad) {
}
@Override
public void onHidden() {
reLoadAd();
goApply();
}
@Override
public void onLoadFail(String string, MaxError maxError) {
}
@Override
public void onLoadSuccess(MaxAd ad) {
}
});
cacheAd.showAd();
} else {
goApply();
}
}
private void reLoadAd() {
for (int i = 0; i < maxInterstitialAds.size(); i++) {
MaxInterstitialAd maxInterstitialAd = maxInterstitialAds.get(i);
if (!maxInterstitialAd.isReady()) {
Log.d("-------","--------reLoadAd "+maxInterstitialAd.getAdUnitId());
maxInterstitialAd.loadAd();
}
}
}
private void goApply() {
progressBarDownload.setVisibility(View.VISIBLE);
String skinPathByName = MyTools.getSkinPathByName(name);
if (!skinPathByName.isEmpty()) {
setCurrentKeyboardSkin(skinPathByName);
progressBarDownload.setVisibility(View.GONE);
Toast.makeText(PreviewActivity.this, getString(R.string.set_successful), Toast.LENGTH_SHORT).show();
finish();
return;
}
MyTools.downloadZip(url, this, new DownloadCallback() {
@Override
public void onDownloadCall(boolean successful, File resource) {
if (successful) {
MyTools.unzipFile(unzipPath, resource, new UnzipCallback() {
@Override
public void onUnzipCall(boolean successful, String resDirPath) {
progressBarDownload.setVisibility(View.GONE);
if (successful) {
MyTools.saveSkinByName(name, resDirPath);
setCurrentKeyboardSkin(resDirPath);
Toast.makeText(PreviewActivity.this, getString(R.string.set_successful), Toast.LENGTH_SHORT).show();
finish();
}
}
});
} else {
progressBarDownload.setVisibility(View.GONE);
}
}
});
}
private void setCurrentKeyboardSkin(String resDirPath) {
MyTools.saveSkin(resDirPath);
}
}

View File

@ -0,0 +1,98 @@
package com.keyboardskinning.theme.ui;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.keyboardskinning.theme.R;
import com.keyboardskinning.theme.tools.MyTools;
public class SettingActivity extends AppCompatActivity {
private BroadcastReceiver broadcastReceiver;
private ImageView imageViewBack;
private TextView textViewStep1;
private TextView textViewStep2;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting);
findView();
broadcastReceiver = new inputReceive();
registerReceiver(broadcastReceiver, new IntentFilter(Intent.ACTION_INPUT_METHOD_CHANGED));
refreshStatus();
setListener();
}
private void findView(){
imageViewBack = findViewById(R.id.image_view_back_id);
textViewStep1 = findViewById(R.id.textview_step1);
textViewStep2 = findViewById(R.id.textview_step2);
}
private void setListener(){
imageViewBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
textViewStep1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyTools.goSetStep1(SettingActivity.this);
}
});
textViewStep2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyTools.goSetStep2();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
private void refreshStatus() {
textViewStep2.setSelected(MyTools.isStep2());
textViewStep1.setSelected(MyTools.isStep1());
}
@Override
protected void onResume() {
super.onResume();
refreshStatus();
}
class inputReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
refreshStatus();
}
}
}

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="9dp"/>
<solid android:color="@color/color_d9c7ff"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/color_d9c7ff"/>
</shape>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M830.3,170.3H437.6A178.3,178.3 0,0 0,310.7 223L58.2,475.3a61.5,61.5 0,0 0,0 86.9l252.3,252.3a178.3,178.3 0,0 0,127.1 52.7h392.7A152.9,152.9 0,0 0,983 714.5V323a152.9,152.9 0,0 0,-152.7 -152.7zM760.2,628.8a25.6,25.6 0,0 1,-36.1 36.1L614.1,554.8 504,664.9a25.6,25.6 0,1 1,-36.1 -36.1L578,518.7 467.9,408.5A25.6,25.6 0,1 1,504 372.4l110.1,110.3L724.1,372.4a25.6,25.6 0,0 1,36.1 0,25.6 25.6,0 0,1 0,36.3L650.1,518.7z"/>
</vector>

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M459.7,155.7l-5.5,4.1 -2.4,2 -3.8,3.5 -2.2,2.2 -3.5,3.8 -258.1,305.9 -4.2,5.4c-28.1,40.2 -20.7,93.3 16,123.6l5.9,4.4 3,2 4.9,2.9 5.6,2.8c13,6.1 26.2,8.9 39.5,8.9l58.6,-0 0,142.6 0.2,6.1c4,48.9 44,85.3 91.9,85.3h212.4l6.1,-0.2 2.7,-0.2 4.8,-0.6 4.7,-0.9c43.4,-9.4 73.7,-46.3 73.7,-89.5l-0,-142.6h58.8l6.1,-0.2c35.6,-2.9 65.4,-24.3 78.7,-55.7a90.9,90.9 0,0 0,-14.2 -94.1L582.4,172.4l-4.6,-5 -1.1,-1.1a92.6,92.6 0,0 0,-117.1 -10.6zM525.3,213.9l2.1,1.8 2.7,2.9 255.9,303.5a21,21 0,0 1,3.4 21.9,22.2 22.2,0 0,1 -18.7,13.3l-3.3,0.1 -127.1,-0v212.4l-0.2,2.6a21.9,21.9 0,0 1,-18.3 18.7l-1.5,0.2 -3.7,0.2L405.6,791.3a22,22 0,0 1,-22.2 -19.9l-0.1,-3.2v-210.9h-128.5l-2.8,-0.2a22.8,22.8 0,0 1,-8 -2.5l-1.7,-1 -3.3,-2.4c-7.4,-6.1 -9.1,-18.4 -2.7,-27.5l2.2,-2.9L494.6,217.4l1.4,-1.5 1.5,-1.3 2.9,-2.2c6.8,-4.6 17.3,-4.1 24.9,1.5z"
android:fillColor="#FFFFFF"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M395.2,513.6l323.1,-312.4c19.1,-18.4 19.1,-48.3 0,-66.7 -19.1,-18.4 -49.9,-18.4 -69,0L291.8,480.3c-19.1,18.4 -19.1,48.3 0,66.7l357.6,345.7c9.5,9.2 22,13.8 34.5,13.8 12.5,0 25,-4.6 34.5,-13.8 19.1,-18.4 19.1,-48.2 0,-66.7L395.2,513.6z"
android:fillColor="#272636"/>
</vector>

View File

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M512.5,955.4c-5.2,0 -10.3,-2.1 -14.1,-6.3 -7,-7.8 -6.4,-19.8 1.4,-26.8l189.5,-170.6c7.8,-7 19.8,-6.4 26.8,1.4 7,7.8 6.4,19.8 -1.4,26.8L525.2,950.6c-3.6,3.2 -8.1,4.8 -12.7,4.8z"
android:fillColor="#ffffff"/>
<path
android:pathData="M512.5,955.4c-4.6,0 -9.1,-1.7 -12.7,-4.9L310.4,780c-7.8,-7 -8.4,-19 -1.4,-26.8 7,-7.8 19,-8.4 26.8,-1.4l157.9,142.1V462.7c0,-10.5 8.5,-19 19,-19s19,8.5 19,19v473.8c0,7.5 -4.4,14.3 -11.2,17.3 -2.7,1.1 -5.3,1.6 -8,1.6z"
android:fillColor="#ffffff"/>
<path
android:pathData="M758.9,690.1c-10.5,0 -19,-8.5 -19,-19s8.5,-19 19,-19c98.8,0 170.6,-72 170.6,-171.2 0,-95.5 -60.1,-162.2 -153.2,-170 -7.2,-0.6 -13.4,-5.2 -16.1,-12C737,240 666.4,102.7 512.5,102.7S288.1,240 264.9,299.1c-2.6,6.7 -8.9,11.4 -16.1,12 -93.1,7.8 -153.2,74.5 -153.2,170 0,99.2 71.7,171.2 170.6,171.2 10.5,0 19,8.5 19,19s-8.5,19 -19,19c-120.8,0 -208.5,-87.9 -208.5,-209.1 0,-110.8 70.3,-192.4 176.2,-206.5C289.4,142.9 392.8,64.8 512.5,64.8S735.7,143 791.1,274.6c105.9,14 176.2,95.7 176.2,206.5 0.1,121.1 -87.6,209 -208.4,209z"
android:fillColor="#ffffff"/>
</vector>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="9dp"/>
<solid android:color="@color/color_d9c7ff"/>
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="9dp"/>
<solid android:color="@color/color_DCDCDC"/>
</shape>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="false" android:drawable="@drawable/step_background"/>
<item android:state_selected="true" android:drawable="@drawable/step_background_selected"/>
</selector>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.ActivityHome">
<ImageView
android:id="@+id/icon"
android:layout_width="83dp"
android:layout_height="83dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="260dp"
android:src="@mipmap/icon2" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/icon"
android:indeterminateTint="@color/color_d9c7ff"
android:layout_centerHorizontal="true"
android:layout_marginTop="73dp" />
</RelativeLayout>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/recycler_view_id"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".ui.MainActivity">
<ImageView
android:id="@+id/image_view_back_id"
android:layout_width="55dp"
android:layout_height="55dp"
android:padding="15dp"
android:src="@drawable/icon_back"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/image_view_preview_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="13dp"
android:layout_marginEnd="15dp"
app:layout_constraintTop_toBottomOf="@id/image_view_back_id" />
<TextView
android:id="@+id/text_view_name_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:textSize="16sp"
android:textColor="@color/color_text_0e0701"
app:layout_constraintLeft_toLeftOf="@id/image_view_preview_id"
app:layout_constraintTop_toBottomOf="@id/image_view_preview_id" />
<LinearLayout
android:id="@+id/linear_layout_download_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="35dp"
android:layout_marginTop="35dp"
android:layout_marginEnd="35dp"
android:background="@drawable/btn_download_background"
android:orientation="vertical"
android:paddingTop="14dp"
android:paddingBottom="14dp"
app:layout_constraintTop_toBottomOf="@id/text_view_name_id">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center"
android:src="@drawable/icon_download" />
</LinearLayout>
<ProgressBar
android:id="@+id/progress_bar_preview_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateTint="@color/color_d9c7ff"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/image_view_preview_id"
app:layout_constraintLeft_toLeftOf="@id/image_view_preview_id"
app:layout_constraintRight_toRightOf="@id/image_view_preview_id"
app:layout_constraintTop_toTopOf="@id/image_view_preview_id" />
<ProgressBar
android:id="@+id/progress_bar_download_id"
android:layout_width="wrap_content"
android:visibility="gone"
android:layout_height="wrap_content"
android:indeterminateTint="@color/color_faa052"
app:layout_constraintBottom_toBottomOf="@id/linear_layout_download_id"
app:layout_constraintLeft_toLeftOf="@id/linear_layout_download_id"
app:layout_constraintRight_toRightOf="@id/linear_layout_download_id"
app:layout_constraintTop_toTopOf="@id/linear_layout_download_id" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_view_back_id"
android:layout_width="55dp"
android:layout_height="55dp"
android:padding="15dp"
android:src="@drawable/icon_back"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="55dp"
android:textSize="16sp"
app:layout_constraintTop_toTopOf="parent"
android:gravity="center"
android:text="@string/set"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:textColor="@color/color_text_0e0701"/>
<TextView
android:layout_width="200dp"
android:layout_height="wrap_content"
android:padding="12dp"
android:id="@+id/textview_step1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="190dp"
android:textColor="@color/white"
android:textSize="17sp"
android:gravity="center"
android:text="@string/step1"
android:background="@drawable/step_selector"
app:layout_constraintTop_toBottomOf="@id/image_view_back_id" />
<TextView
android:layout_width="200dp"
android:layout_height="wrap_content"
android:padding="12dp"
android:id="@+id/textview_step2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="14dp"
android:textColor="@color/white"
android:textSize="17sp"
android:gravity="center"
android:text="@string/step2"
android:background="@drawable/step_selector"
app:layout_constraintTop_toBottomOf="@id/textview_step1" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.keyboardskinning.theme.tools.MyKeyBoardView
android:id="@+id/my_keyboard_view"
android:layout_width="match_parent"
android:layout_height="210dp"
android:padding="2dp"
android:keyBackground="@drawable/de_keyboard_bg" />
</LinearLayout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:id="@+id/constraint_layout_id"
android:layout_height="wrap_content"
tools:context=".ui.MainActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="110dp"
android:scaleType="fitXY"
android:id="@+id/image_view_thumb_id"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="color_d9c7ff">#d9c7ff</color>
<color name="color_faa052">#faa052</color>
<color name="color_text_0e0701">#0e0701</color>
<color name="color_DCDCDC">#DCDCDC</color>
</resources>

View File

@ -0,0 +1,8 @@
<resources>
<string name="app_name">KeyboardSkinning</string>
<string name="step1">Step One</string>
<string name="step2">Step Two</string>
<string name="text_hint">For normal use, please enter the setting to complete the setting steps.</string>
<string name="set_successful">Apply the keyboard skin successfully</string>
<string name="set">Settings</string>
</resources>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="style_view_keyboard">
<attr name="android:keyBackground"/>
<attr name="android:keyTextSize"/>
<attr name="android:labelTextSize"/>
<attr name="android:keyTextColor"/>
<attr name="android:keyPreviewLayout"/>
<attr name="android:keyPreviewOffset"/>
<attr name="android:keyPreviewHeight"/>
<attr name="android:verticalCorrection"/>
<attr name="android:popupLayout"/>
<attr name="android:shadowColor"/>
<attr name="android:shadowRadius"/>
</declare-styleable>
<declare-styleable name="style_row">
<attr name="android:rowEdgeFlags"/>
<attr name="android:keyboardMode"/>
</declare-styleable>
<declare-styleable name="style_key">
<attr name="android:codes"/>
<attr name="android:popupKeyboard"/>
<attr name="android:popupCharacters"/>
<attr name="android:keyEdgeFlags"/>
<attr name="android:isModifier"/>
<attr name="android:isSticky"/>
<attr name="android:isRepeatable"/>
<attr name="android:iconPreview"/>
<attr name="android:keyOutputText"/>
<attr name="android:keyLabel"/>
<attr name="android:keyIcon"/>
<attr name="android:keyboardMode"/>
</declare-styleable>
<declare-styleable name="Style_Pre_state">
<attr name="android:state_long_pressable"/>
</declare-styleable>
<declare-styleable name="style_view">
<attr name="android:keyWidth"/>
<attr name="android:keyHeight"/>
<attr name="android:horizontalGap"/>
<attr name="android:verticalGap"/>
</declare-styleable>
</resources>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.KeyboardSkinning" parent="Theme.MaterialComponents.DayNight.NoActionBar" >
<item name="android:statusBarColor">@color/color_d9c7ff</item>
</style>
</resources>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<subtype
android:icon="@drawable/ic_launcher_background"
android:imeSubtypeLocale="en_US"
android:imeSubtypeMode = "keyboard"
android:label="@string/app_name" />
</input-method>

View File

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:keyHeight="50dp">
<Row
android:keyWidth="9.45%"
android:keyHeight="50dp"
android:horizontalGap="0.5%"
android:rowEdgeFlags="top">
<Key
android:codes="113"
android:keyEdgeFlags="left"
android:keyLabel="q" />
<Key
android:codes="119"
android:keyLabel="w" />
<Key
android:codes="101"
android:keyLabel="e" />
<Key
android:codes="114"
android:keyLabel="r" />
<Key
android:codes="116"
android:keyLabel="t" />
<Key
android:codes="121"
android:keyLabel="y" />
<Key
android:codes="117"
android:keyLabel="u" />
<Key
android:codes="105"
android:keyLabel="i" />
<Key
android:codes="111"
android:keyLabel="o" />
<Key
android:codes="112"
android:keyEdgeFlags="right"
android:keyLabel="p" />
</Row>
<Row
android:keyWidth="9.444444%"
android:keyHeight="50dp"
android:horizontalGap="0.5%">
<Key
android:codes="97"
android:horizontalGap="5.5%"
android:keyLabel="a" />
<Key
android:codes="115"
android:keyLabel="s" />
<Key
android:codes="100"
android:keyLabel="d" />
<Key
android:codes="102"
android:keyLabel="f" />
<Key
android:codes="103"
android:keyLabel="g" />
<Key
android:codes="104"
android:keyLabel="h" />
<Key
android:codes="106"
android:keyLabel="j" />
<Key
android:codes="107"
android:keyLabel="k" />
<Key
android:codes="108"
android:keyLabel="l" />
</Row>
<Row
android:keyHeight="50dp"
android:keyWidth="9.5%"
android:horizontalGap="0.5%">
<Key
android:codes="-1"
android:isModifier="true"
android:isSticky="true"
android:keyWidth="14.25%"
android:keyEdgeFlags="left" />
<Key
android:codes="122"
android:keyLabel="z" />
<Key
android:codes="120"
android:keyLabel="x" />
<Key
android:codes="99"
android:keyLabel="c" />
<Key
android:codes="118"
android:keyLabel="v" />
<Key
android:codes="98"
android:keyLabel="b" />
<Key
android:codes="110"
android:keyLabel="n" />
<Key
android:codes="109"
android:keyLabel="m" />
<Key
android:codes="-5"
android:isModifier="true"
android:isRepeatable="true"
android:keyWidth="14.25%"
android:keyEdgeFlags="right" />
</Row>
<Row
android:horizontalGap="0.5%"
android:keyHeight="50dp"
android:rowEdgeFlags="bottom"
android:keyWidth="9.5%">
<Key
android:codes="-2"
android:keyWidth="14.25%"
android:keyEdgeFlags="left"
android:keyLabel="\?123" />
<Key
android:codes="44"
android:keyLabel="," />
<Key
android:codes="32"
android:keyWidth="49.5%"
android:keyLabel="English" />
<Key
android:codes="46"
android:keyLabel="." />
<Key
android:codes="-4"
android:keyWidth="14.25%"
android:keyLabel="Done"
android:keyEdgeFlags="right" />
</Row>
</Keyboard>

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android">
<Row
android:keyWidth="9.45%"
android:keyHeight="50dp"
android:horizontalGap="0.5%"
android:rowEdgeFlags="top">
<Key
android:codes="49"
android:keyEdgeFlags="left"
android:keyLabel="1" />
<Key android:keyLabel="2"
android:codes="50"/>
<Key android:keyLabel="3"
android:codes="51"/>
<Key android:keyLabel="4"
android:codes="52"/>
<Key android:keyLabel="5"
android:codes="53"/>
<Key android:keyLabel="6"
android:codes="54"/>
<Key android:keyLabel="7"
android:codes="55"/>
<Key android:keyLabel="8"
android:codes="56"/>
<Key android:keyLabel="9"
android:codes="57"/>
<Key
android:keyEdgeFlags="right"
android:codes="48"
android:keyLabel="0" />
</Row>
<Row
android:keyWidth="9.444444%"
android:keyHeight="50dp"
android:horizontalGap="0.5%">
<Key
android:keyEdgeFlags="left"
android:keyLabel="\@"
android:horizontalGap="5.5%"
android:codes="64"/>
<Key android:keyLabel="#"
android:codes="35"/>
<Key android:keyLabel="\$"
android:codes="36"/>
<Key android:keyLabel="%"
android:codes="37"/>
<Key android:keyLabel="&amp;"
android:codes="38"/>
<Key android:keyLabel="-"
android:codes="45"/>
<Key android:keyLabel="+"
android:codes="43"/>
<Key android:keyLabel="("
android:codes="40"/>
<Key
android:keyEdgeFlags="right"
android:codes="41"
android:keyLabel=")" />
</Row>
<Row
android:keyHeight="50dp"
android:keyWidth="9.5%"
android:horizontalGap="0.5%">
<Key
android:codes="-360"
android:isModifier="true"
android:keyWidth="14.25%"
android:keyLabel="more"
android:keyEdgeFlags="left" />
<Key android:keyLabel="*"
android:codes="42" />
<Key android:keyLabel="&#034;"
android:codes="34" />
<Key android:keyLabel="'"
android:codes="39" />
<Key android:keyLabel=":"
android:codes="58" />
<Key android:keyLabel=";"
android:codes="59" />
<Key android:keyLabel="!"
android:codes="33" />
<Key android:keyLabel="\?"
android:codes="63" />
<!--delete-->
<Key
android:codes="-5"
android:keyWidth="14.25%"
android:isModifier="true"
android:isRepeatable="true"
android:keyEdgeFlags="right" />
</Row>
<Row
android:horizontalGap="0.5%"
android:keyHeight="50dp"
android:rowEdgeFlags="bottom"
android:keyWidth="9.5%">
<Key
android:codes="-2"
android:keyWidth="14.25%"
android:keyEdgeFlags="left"
android:keyLabel="ABC" />
<Key android:keyLabel=","
android:codes="44" />
<Key android:keyLabel="_"
android:codes="95" />
<Key
android:codes="32"
android:keyWidth="29.5%"
android:keyLabel="English" />
<Key android:keyLabel="/"
android:codes="47" />
<Key android:keyLabel="."
android:codes="46" />
<Key
android:codes="-4"
android:keyLabel="Done"
android:keyWidth="14.25%"
android:keyEdgeFlags="right" />
</Row>
</Keyboard>

View File

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android">
<Row
android:keyWidth="9.45%"
android:keyHeight="50dp"
android:horizontalGap="0.5%"
android:rowEdgeFlags="top">
<Key
android:codes="126"
android:keyEdgeFlags="left"
android:keyLabel="~" />
<Key android:keyLabel="`"
android:codes="96"/>
<Key android:keyLabel="|"
android:codes="124"/>
<Key android:keyLabel="•"
android:codes="149"/>
<Key android:keyLabel="✔"
android:codes="10004"/>
<Key android:keyLabel="π"
android:codes="960"/>
<Key android:keyLabel="÷"
android:codes="247"/>
<Key android:keyLabel="×"
android:codes="215"/>
<Key android:keyLabel="¶"
android:codes="182"/>
<Key
android:keyEdgeFlags="right"
android:codes="8710"
android:keyLabel="∆" />
</Row>
<Row
android:keyWidth="9.444444%"
android:keyHeight="50dp"
android:horizontalGap="0.5%">
<Key
android:keyEdgeFlags="left"
android:keyLabel="£"
android:horizontalGap="5.5%"
android:codes="163"/>
<Key android:keyLabel="¢"
android:codes="65504"/>
<Key android:keyLabel="€"
android:codes="8364"/>
<Key android:keyLabel="¥"
android:codes="165"/>
<Key android:keyLabel="^"
android:codes="94"/>
<Key android:keyLabel="°"
android:codes="176"/>
<Key android:keyLabel="="
android:codes="61"/>
<Key android:keyLabel="{"
android:codes="123"/>
<Key
android:keyEdgeFlags="right"
android:codes="125"
android:keyLabel="}" />
</Row>
<Row
android:keyHeight="50dp"
android:keyWidth="9.5%"
android:horizontalGap="0.5%">
<Key
android:codes="-361"
android:isModifier="true"
android:keyWidth="14.25%"
android:keyLabel="\?123"
android:keyEdgeFlags="left" />
<Key android:keyLabel="\\"
android:codes="92" />
<Key android:keyLabel="Ⓒ"
android:codes="9400" />
<Key android:keyLabel="®"
android:codes="174" />
<Key android:keyLabel="™"
android:codes="8482" />
<Key android:keyLabel="℅"
android:codes="8453" />
<Key android:keyLabel="["
android:codes="91" />
<Key android:keyLabel="]"
android:codes="93" />
<Key
android:codes="-5"
android:keyWidth="14.25%"
android:isModifier="true"
android:isRepeatable="true"
android:keyEdgeFlags="right" />
</Row>
<Row
android:horizontalGap="0.5%"
android:keyHeight="50dp"
android:rowEdgeFlags="bottom"
android:keyWidth="9.5%">
<Key
android:codes="-2"
android:keyWidth="14.25%"
android:keyEdgeFlags="left"
android:keyLabel="ABC" />
<Key android:keyLabel=","
android:codes="46" />
<Key android:keyLabel="&lt;"
android:codes="60" />
<Key
android:codes="32"
android:keyWidth="29.5%"
android:keyLabel="English" />
<Key android:keyLabel="&gt;"
android:codes="62" />
<Key android:keyLabel="."
android:codes="46" />
<Key
android:codes="-4"
android:keyLabel="Done"
android:keyWidth="14.25%"
android:keyEdgeFlags="right" />
</Row>
</Keyboard>

View File

@ -0,0 +1,17 @@
package com.keyboardskinning.theme
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit theme, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

Binary file not shown.

12
build.gradle.kts Normal file
View File

@ -0,0 +1,12 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.1.3" apply false
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
id("com.google.gms.google-services") version "4.3.15" apply false
id ("com.google.firebase.crashlytics") version "2.9.2" apply false
}
buildscript{
dependencies{
classpath("com.applovin.quality:AppLovinQualityServiceGradlePlugin:+")
}
}

23
gradle.properties Normal file
View File

@ -0,0 +1,23 @@
# 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. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec: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
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# 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

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Mon Mar 11 11:05:07 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
gradlew vendored Normal file
View File

@ -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" "$@"

89
gradlew.bat vendored Normal file
View File

@ -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

22
settings.gradle.kts Normal file
View File

@ -0,0 +1,22 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
maven{url = uri("https://artifacts.applovin.com/android")}
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven("https://jitpack.io")
maven ("https://artifact.bytedance.com/repository/pangle")
}
}
rootProject.name = "KeyboardSkinning"
include(":app")