This commit is contained in:
2025-12-05 18:19:49 +08:00
commit 2a74fd2c30
1439 changed files with 94814 additions and 0 deletions

1
libapputils/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

40
libapputils/build.gradle Normal file
View File

@@ -0,0 +1,40 @@
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply from: '../.winboll/winboll_lib_build.gradle'
apply from: '../.winboll/winboll_lint_build.gradle'
android {
compileSdkVersion 32
buildToolsVersion "32.0.0"
defaultConfig {
minSdkVersion 24
targetSdkVersion 30
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
api fileTree(dir: 'libs', include: ['*.jar'])
api 'cc.winboll.studio:libappbase:15.10.9'
// 二维码类库
api 'com.google.zxing:core:3.4.1'
api 'com.journeyapps:zxing-android-embedded:3.6.0'
// 网络连接类库
api 'com.squareup.okhttp3:okhttp:4.4.1'
// Html 解析
api 'org.jsoup:jsoup:1.13.1'
api 'com.google.code.gson:gson:2.10.1'
// SSH
//api 'com.jcraft:jsch:0.1.55'
}

View File

@@ -0,0 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Mon Sep 29 01:15:55 HKT 2025
stageCount=3
libraryProject=libapputils
baseVersion=15.10
publishVersion=15.10.2
buildCount=0
baseBetaVersion=15.10.3

17
libapputils/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:/tools/adt-bundle-windows-x86_64-20131030/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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 *;
#}

View File

@@ -0,0 +1,29 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.libapputils">
<!-- 此应用可显示在其他应用上方 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<!-- 对正在运行的应用重新排序 -->
<uses-permission android:name="android.permission.REORDER_TASKS"/>
<!-- MOVE_TASK_TO_FRONT -->
<uses-permission android:name="android.permission.MOVE_TASK_TO_FRONT"/>
<!-- 检索正在运行的应用 -->
<uses-permission android:name="android.permission.GET_TASKS"/>
<!-- 拍摄照片和视频 -->
<uses-permission android:name="android.permission.CAMERA"/>
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:networkSecurityConfig="@xml/network_security_config">
</application>
</manifest>

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device - width, initial - scale = 1.0">
<title>WinBoLL-APP</title>
</head>
<body>
<h2><a href="https://www.winboll.cc">访问 WWW.WinBoLL.CC</a></h2>
</body>
</html>

View File

@@ -0,0 +1,241 @@
<!DOCTYPE html>
<html lang="en">
<!--
JavaScript实现在HTML中的粒子文字特效
来源https://blog.csdn.net/m0_46700215/article/details/126963561?sharetype=blog&shareId=126963561&sharerefer=APP&sharesource=weixin_38986226
-->
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device - width, initial - scale = 1.0">
<title>WinBoLL</title>
</head>
<body>
<canvas id="ChangeText">WinBoLL Studio</canvas>
<script type="text/javascript">
const COLOR = "#39BC54"; // 设定粒子特效颜色
let MESSAGE = document.getElementById("ChangeText").textContent; // 根据标签的ID获取待处理的文字内容
let FONT_SIZE = (window.innerWidth * 0.08); // 字体大小
let AMOUNT = 6000; // 设定粒子数量
let SIZE = 2; // 粒子大小
let INITIAL_DISPLACEMENT = 500; // 最初位移量
const INITIAL_VELOCITY = 7.5; // 最初速度
const VELOCITY_RETENTION = 0.95; // 速度保持
let SETTLE_SPEED = 1; // 稳定速度
const FLEE_SPEED = 2; // 逃逸速度
const FLEE_DISTANCE = 50; // 逃逸距离
let FLEE = true; // 逃逸模式
let SCATTER_VELOCITY = 3; // 散射速度
const SCATTER = true; // 散射模式
// 若处于移动设备展示
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
// Mobile
MESSAGE = document.getElementById("ChangeText").textContent; // 通过标签ID获取文本内容
FONT_SIZE = 50; // 字体大小减小
AMOUNT = 2000; // 粒子数量减少
SIZE = 1;
INITIAL_DISPLACEMENT = 100; // 最初位移量减少
SETTLE_SPEED = 1; // 最初速度减少
FLEE = false; // 关闭逃逸模式
SCATTER_VELOCITY = 2; // 散射速度
}
const canvas = document.getElementById("ChangeText");
const ctx = canvas.getContext("2d"); // 创建画布
let POINTS = [];
const MOUSE = {
x: 0,
y: 0
};
function Point(x, y, r, g, b, a) {
const angle = Math.random() * 6.28;
this.x = canvas.width / 2 - x + (Math.random() - 0.5) * INITIAL_DISPLACEMENT;
this.y = canvas.height / 2 - y + (Math.random() - 0.5) * INITIAL_DISPLACEMENT;
this.velx = INITIAL_VELOCITY * Math.cos(angle);
this.vely = INITIAL_VELOCITY * Math.sin(angle);
this.target_x = canvas.width / 2 - x;
this.target_y = canvas.height / 2 - y;
this.r = r;
this.g = g;
this.b = b;
this.a = a;
this.getX = function () {
return this.x;
}
this.getY = function () {
return this.y;
}
this.fleeFrom = function () {
this.velx -= ((MOUSE.x - this.x) * FLEE_SPEED / 10);
this.vely -= ((MOUSE.y - this.y) * FLEE_SPEED / 10);
}
this.settleTo = function () {
this.velx += ((this.target_x - this.x) * SETTLE_SPEED / 100);
this.vely += ((this.target_y - this.y) * SETTLE_SPEED / 100);
this.velx -= this.velx * (1 - VELOCITY_RETENTION);
this.vely -= this.vely * (1 - VELOCITY_RETENTION);
}
this.scatter = function () {
const unit = this.unitVecToMouse();
const vel = SCATTER_VELOCITY * 10 * (0.5 + Math.random() / 2);
this.velx = -unit.x * vel;
this.vely = -unit.y * vel;
}
this.move = function () {
if (this.distanceToMouse() <= FLEE_DISTANCE) {
this.fleeFrom();
} else {
this.settleTo();
}
if (this.x + this.velx < 0 || this.x + this.velx >= canvas.width) {
this.velx *= -1;
}
if (this.y + this.vely < 0 || this.y + this.vely >= canvas.height) {
this.vely *= -1;
}
this.x += this.velx;
this.y += this.vely;
}
this.distanceToMouse = function () {
return this.distanceTo(MOUSE.x, MOUSE.y);
}
this.distanceTo = function (x, y) {
return Math.sqrt((x - this.x) * (x - this.x) + (y - this.y) * (y - this.y));
}
this.unitVecToMouse = function () {
return this.unitVecTo(MOUSE.x, MOUSE.y);
}
this.unitVecTo = function (x, y) {
const dx = x - this.x;
const dy = y - this.y;
return {
x: dx / Math.sqrt(dx * dx + dy * dy),
y: dy / Math.sqrt(dx * dx + dy * dy)
};
}
}
window.addEventListener("resize", function () {
resizeCanvas()
adjustText()
});
if (FLEE) {
window.addEventListener("mousemove", function (event) {
MOUSE.x = event.clientX;
MOUSE.y = event.clientY;
});
}
if (SCATTER) {
window.addEventListener("click", function (event) {
MOUSE.x = event.clientX;
MOUSE.y = event.clientY;
for (let i = 0; i < POINTS.length; i++) {
POINTS[i].scatter();
}
});
}
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function adjustText() {
ctx.fillStyle = COLOR;
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.font = FONT_SIZE + "px Arial";
ctx.fillText(MESSAGE, canvas.width / 2, canvas.height / 2);
const textWidth = ctx.measureText(MESSAGE).width;
if (textWidth === 0) {
return;
}
const minX = canvas.width / 2 - textWidth / 2;
const minY = canvas.height / 2 - FONT_SIZE / 2;
const data = ctx.getImageData(minX, minY, textWidth, FONT_SIZE).data;
let isBlank = true;
for (let i = 0; i < data.length; i++) {
if (data[i] !== 0) {
isBlank = false;
break;
}
}
if (!isBlank) {
let count = 0;
let curr = 0;
let num = 0;
let x = 0;
let y = 0;
const w = Math.floor(textWidth);
POINTS = [];
while (count < AMOUNT) {
while (curr === 0) {
num = Math.floor(Math.random() * data.length);
curr = data[num];
}
num = Math.floor(num / 4);
x = w / 2 - num % w;
y = FONT_SIZE / 2 - Math.floor(num / w);
POINTS.push(new Point(x, y, data[num * 4], data[num * 4 + 1], data[num * 4 + 2], data[num * 4 + 3]));
curr = 0;
count++;
}
}
}
function init() {
resizeCanvas()
adjustText()
window.requestAnimationFrame(animate);
}
function animate() {
update();
draw();
}
function update() {
let point;
for (let i = 0; i < POINTS.length; i++) {
point = POINTS[i];
point.move();
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
let point;
for (let i = 0; i < POINTS.length; i++) {
point = POINTS[i];
ctx.fillStyle = "rgba(" + point.r + "," + point.g + "," + point.b + "," + point.a + ")";
ctx.beginPath();
ctx.arc(point.getX(), point.getY(), SIZE, 0, 2 * Math.PI);
ctx.fill();
}
window.requestAnimationFrame(animate);
}
init();
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,59 @@
package cc.winboll.studio.libapputils.git;
import android.content.Context;
import cc.winboll.studio.libappbase.LogUtils;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/12/09 12:30:59
* @Describe 应用文件接口基础类
*/
public interface IAPPFiles {
public static final String TAG = "IAPPFiles";
public static final String UUID_LOGUTILS_JSON = "cef58919-88a6-47c4-9e10-44d8c810328e";
public static final String UUID_WINBOLLCLIENTSERVICEBEAN_JSON = "d7816eda-9724-4a86-b9d5-43eeee7be76d";
public static final String APPRoot = "";
HashFile getFile(String szAPPFilesURI);
class HashFile {
static Map<String, String> _mapFiles = new HashMap<String, String>();
volatile static HashFile _mHashFile;
File mFile;
static String _mFilesRoot = "";
HashFile(Context context) {
_mapFiles.put(UUID_WINBOLLCLIENTSERVICEBEAN_JSON, "/BaseBean/cc.winboll.studio.shared.service.WinBoLLClientServiceBean.json");
_mapFiles.put(UUID_LOGUTILS_JSON, "/LogUtils/LogUtils.json");
}
synchronized static HashFile getInstance(Context context, String uuid) throws IOException {
if (_mHashFile == null) {
_mHashFile = new HashFile(context);
}
try {
_mHashFile.mFile = new File(context.getExternalFilesDir("") + _mapFiles.get(uuid));
} catch (Exception e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
} finally {
if (_mHashFile.mFile == null) {
LogUtils.d(TAG, "_mHashFile.mFile == null");
}
}
return _mHashFile;
}
static File getFileByUUID(Context context, String uuid) throws IOException {
return new File(getInstance(context, uuid)._mapFiles.get(uuid));
}
}
//class HashFileManager
}

View File

@@ -0,0 +1,29 @@
package cc.winboll.studio.libapputils.utils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/02/15 20:05:03
* @Describe AppUtils
*/
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import cc.winboll.studio.libappbase.LogUtils;
public class AppUtils {
public static final String TAG = "AppUtils";
public static String getAppNameByPackageName(Context context, String packageName) {
PackageManager packageManager = context.getPackageManager();
try {
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
return (String) packageManager.getApplicationLabel(applicationInfo);
} catch (NameNotFoundException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
return "";
}
}
}

View File

@@ -0,0 +1,179 @@
package cc.winboll.studio.libapputils.utils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/03/23 16:17:54
* @Describe 哔哔振动响铃工具集
*/
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Handler;
import android.os.Vibrator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class BBMorseCodeUtils {
public static final String TAG = "BBMorseCodeUtils";
// private static final int DOT_DURATION = 100; // 点时长 (ms)
// private static final int DASH_DURATION = 300; // 划时长 (ms)
// private static final int SYMBOL_GAP = 100; // 符号间隔 (ms)
// private static final int CHARACTER_GAP = 300; // 字符间隔 (ms)
// private static final int WORD_GAP = 700; // 单词间隔 (ms)
//
// private final Context context;
// private final Handler handler = new Handler();
// private boolean isPlaying = false;
//
// public BBMorseCodeUtils(Context context) {
// this.context = context.getApplicationContext();
// }
//
// public void playMorseCode(String morseCode, boolean vibrateEnabled, boolean ringEnabled) {
// if (isPlaying) return;
// isPlaying = true;
//
// List<List<String>> words = parseMorseCode(morseCode);
// startSequence(words, vibrateEnabled, ringEnabled);
// }
//
// private void startSequence(final List<List<String>> words, final boolean vibrateEnabled, final boolean ringEnabled) {
// final int[] wordIndex = {0};
// final int[] charIndex = {0};
// final int[] symbolIndex = {0};
//
// Runnable sequenceRunner = new Runnable() {
// @Override
// public void run() {
// if (wordIndex[0] >= words.size()) {
// stop();
// return;
// }
//
// List<String> characters = words.get(wordIndex[0]);
// if (charIndex[0] >= characters.size()) {
// charIndex[0] = 0;
// symbolIndex[0] = 0;
// wordIndex[0]++;
// handler.postDelayed(this, WORD_GAP);
// return;
// }
//
// String character = characters.get(charIndex[0]);
// if (symbolIndex[0] >= character.length()) {
// symbolIndex[0] = 0;
// charIndex[0]++;
// handler.postDelayed(this, CHARACTER_GAP);
// return;
// }
//
// char symbol = character.charAt(symbolIndex[0]);
// symbolIndex[0]++;
//
// long duration = (symbol == '.') ? DOT_DURATION : DASH_DURATION;
//
// // 执行振动
// if (vibrateEnabled) {
// vibrate(duration);
// }
//
// // 播放声音
// if (ringEnabled) {
// playSound(symbol, duration);
// }
//
// // 安排下一个符号
// handler.postDelayed(this, duration + SYMBOL_GAP);
// }
// };
//
// handler.post(sequenceRunner);
// }
//
// private void vibrate(long duration) {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// VibratorManager vibratorManager = context.getSystemService(VibratorManager.class);
// Vibrator vibrator = vibratorManager.getDefaultVibrator();
// vibrator.vibrate(duration);
// } else {
// Vibrator vibrator = context.getSystemService(Vibrator.class);
// if (vibrator != null && vibrator.hasVibrator()) {
// vibrator.vibrate(duration);
// }
// }
// }
//
// private void playSound(char symbol, long duration) {
// int soundRes = (symbol == '.') ? R.raw.morse_dot : R.raw.morse_dash;
// MediaPlayer mediaPlayer = MediaPlayer.create(context, soundRes);
//
// mediaPlayer.setOnPreparedListener(> {
// mp.start();
// handler.postDelayed(mp::stop, duration);
// });
//
// mediaPlayer.setOnCompletionListener(> {
// mp.release();
// });
// }
//
// private List<List<String>> parseMorseCode(String code) {
// List<List<String>> words = new ArrayList<>();
// String[] wordParts = code.split("/");
//
// for (String word : wordParts) {
// String[] chars = word.trim().split("\\s+");
// words.add(new ArrayList<>(Arrays.asList(chars)));
// }
// return words;
// }
//
// public void stop() {
// isPlaying = false;
// handler.removeCallbacksAndMessages(null);
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// VibratorManager vibratorManager = context.getSystemService(VibratorManager.class);
// Vibrator vibrator = vibratorManager.getDefaultVibrator();
// vibrator.cancel();
// } else {
// Vibrator vibrator = context.getSystemService(Vibrator.class);
// if (vibrator != null) {
// vibrator.cancel();
// }
// }
// }
}
// 使用说明:
//
// 1. 在AndroidManifest.xml中添加权限
//
// xml
//
// <uses-permission android:name="android.permission.VIBRATE"/>
//  
//
// 2. 在res/raw目录下添加两个声音文件
//
// - morse_dot.wav短音
//
// - morse_dash.wav长音
//
// 3. 使用示例:
//
// java
//
// MorsePlayer morsePlayer = new MorsePlayer(this);
//morsePlayer.playMorseCode(".... . / .- --", true, true);
//
// 停止播放
// morsePlayer.stop();
// MorsePlayer morsePlayer = new MorsePlayer(this);
//morsePlayer.playMorseCode(".... . / .- --", true, true);
//
//// 停止播放
//// morsePlayer.stop();
//

View File

@@ -0,0 +1,241 @@
package cc.winboll.studio.libapputils.utils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/07/19 14:30:57
* @Describe 文件工具类
*/
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.net.Uri;
import android.support.v4.content.FileProvider;
import cc.winboll.studio.libappbase.LogUtils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileUtils {
public static final String TAG = "FileUtil";
public static void shareJSONFile(Context context, String szShareFilePath) {
Uri uri;
File file = new File(szShareFilePath);
uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
/*if (Build.VERSION.SDK_INT >= 24) {//android 7.0以上
uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
} else {
uri = Uri.fromFile(file);
}*/
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.setType("application/json");
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
/*if (Build.VERSION.SDK_INT >= 24) {
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}*/
// 设置分享的标题
context.startActivity(Intent.createChooser(shareIntent, "SHARE JSON"));
}
public static void shareHtmlFile(Context context, String szHtmlFile) {
File htmlFile = new File(szHtmlFile);
Uri contentUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", htmlFile);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(contentUri, "text/html");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
}
public static void copyAssetsToSD(Context context, String szSrcAssets, String szDstSD) {
LogUtils.d(TAG, "copyAssetsToSD [" + szSrcAssets + "] to [" + szDstSD + "]");
AssetManager assetManager = context.getAssets();
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = assetManager.open(szSrcAssets);
File outputFile = new File(szDstSD);
outputStream = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int length = 0;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
outputStream.flush();
LogUtils.d(TAG, "copyAssetsToSD done.");
} catch (IOException e) {
LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace());
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace());
}
}
}
}
public static boolean copyFile(File srcFile, File dstFile) {
if (!srcFile.exists()) {
LogUtils.d(TAG, "The original file does not exist.");
} else {
try {
// 源文件路径
Path sourcePath = Paths.get(srcFile.getPath());
// 目标文件路径
Path destPath = Paths.get(dstFile.getPath());
// 建立目标父级文件夹
if (!dstFile.getParentFile().exists()) {
dstFile.getParentFile().mkdirs();
}
// 删除旧的目标文件
if (dstFile.exists()) {
dstFile.delete();
}
// 拷贝文件
Files.copy(sourcePath, destPath);
LogUtils.d(TAG, "File copy successfully.");
return true;
} catch (Exception e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
return false;
}
/**
* 读取文件为字节数组Java 7 语法)
*/
public static byte[] readByteArrayFromFile(String filePath) {
FileInputStream fis = null;
ByteArrayOutputStream bos = null;
try {
fis = new FileInputStream(filePath);
bos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
// 手动关闭流Java 7 不支持 try-with-resources
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 写入字节数组到文件Java 7 语法)
*/
public static boolean writeByteArrayToFile(byte[] data, String filePath) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filePath);
fos.write(data);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static String readStringFromFile(String filePath) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(filePath));
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append(System.getProperty("line.separator"));
}
// 去除最后一个换行符(可选)
if (content.length() > 0) {
content.deleteCharAt(content.length() - 1);
}
return content.toString();
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static boolean writeStringToFile(String content, String filePath, boolean append) {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(filePath, append));
writer.write(content);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

View File

@@ -0,0 +1,37 @@
package cc.winboll.studio.libapputils.utils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/12/19 15:26:58
*/
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Utils {
public static String encrypt(String input) {
try {
// 获取MD5实例
MessageDigest md = MessageDigest.getInstance("MD5");
// 对输入的字符串进行摘要计算,得到字节数组
byte[] messageDigest = md.digest(input.getBytes());
// 将字节数组转换为十六进制的字符串表示形式
BigInteger no = new BigInteger(1, messageDigest);
String hashtext = no.toString(16);
while (hashtext.length() < 32) {
hashtext = "0" + hashtext;
}
return hashtext;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
String str = "要加密的字符串";
String encryptedStr = encrypt(str);
System.out.println(encryptedStr);
}
}

View File

@@ -0,0 +1,33 @@
package cc.winboll.studio.libapputils.utils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/11/28 15:03:12
* @Describe 应用变量保存工具
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.widget.EditText;
public class PrefUtils {
public static final String TAG = "PrefUtils";
//
// 保存字符串到SharedPreferences的函数
//
public static void saveString(Context context, String key, String value) {
SharedPreferences sharedPreferences = context.getSharedPreferences("myPrefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(key, value);
editor.apply();
}
//
// 从SharedPreferences读取字符串的函数
//
public static String getString(Context context, String key, String defaultValue) {
SharedPreferences sharedPreferences = context.getSharedPreferences("myPrefs", Context.MODE_PRIVATE);
return sharedPreferences.getString(key, defaultValue);
}
}

View File

@@ -0,0 +1,58 @@
package cc.winboll.studio.libapputils.utils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/01/17 20:49:55
* @Describe 二维码工具
*/
import android.graphics.Bitmap;
import cc.winboll.studio.libappbase.LogUtils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.journeyapps.barcodescanner.BarcodeEncoder;
public class QRCodeGenerator {
public static final String TAG = "QRCodeGenerator";
// public static void main(String[] args) {
// String qrCodeText = "https://www.example.com";
// String filePath = "qrcode.png";
// int width = 300;
// int height = 300;
// String imageFormat = "png";
//
// generateQRCodeImage(qrCodeText, width, height, imageFormat, filePath);
// // 新增的二维码读取部分
// Result result = decodeQRCode(filePath);
// if (result != null) {
// System.out.println("解码结果: " + result.getText());
// }
// }
public static Bitmap generateQRCodeImage(String qrCodeText, int width, int height) {
// 创建QRCodeWriter对象
QRCodeWriter qrCodeWriter = new QRCodeWriter();
try {
// 使用QRCodeWriter生成BitMatrix
BitMatrix bitMatrix = qrCodeWriter.encode(qrCodeText, BarcodeFormat.QR_CODE, width, height);
// 使用BarcodeEncoder将BitMatrix转化为Bitmap
BarcodeEncoder barcodeEncoder = new BarcodeEncoder();
Bitmap bitmap = barcodeEncoder.createBitmap(bitMatrix);
// 将Bitmap设置给ImageView显示二维码
return bitmap;
} catch (WriterException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
return null;
}
}

View File

@@ -0,0 +1,32 @@
package cc.winboll.studio.libapputils.utils;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/09/01 07:49
* @Describe .* 前置预防针
regex pointer preventive injection
简称 RegexPPi
*/
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexPPiUtils {
public static final String TAG = "RegexPPiUtils";
//
// 检验文本是否满足适合正则表达式模式计算
//
public static boolean isPPiOK(String text) {
//String text = "这里是一些任意的文本内容";
String regex = ".*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
/*if (matcher.matches()) {
System.out.println("文本满足该正则表达式模式");
} else {
System.out.println("文本不满足该正则表达式模式");
}*/
return matcher.matches();
}
}

View File

@@ -0,0 +1,36 @@
package cc.winboll.studio.libapputils.utils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/12/08 20:09:02
* @Describe 应用服务组件工具类
*/
import android.app.ActivityManager;
import android.content.Context;
import java.util.List;
public class ServiceUtils {
public static final String TAG = "ServiceUtils";
public static boolean isServiceAlive(Context context, String szServiceName) {
// 获取Activity管理者对象
ActivityManager manager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
// 获取正在运行的服务此处设置最多取1000个
List<ActivityManager.RunningServiceInfo> runningServices = manager
.getRunningServices(1000);
if (runningServices.size() <= 0) {
return false;
}
// 遍历若存在名字和传入的serviceName的一致则说明存在
for (ActivityManager.RunningServiceInfo runningServiceInfo : runningServices) {
if (runningServiceInfo.service.getClassName().equals(szServiceName)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,130 @@
package cc.winboll.studio.libapputils.utils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Describe Uri 资源管理工具类
*/
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class UriUtils {
public static final String TAG = "UriUtil";
//
// 获取真实路径
//
// @param context
//
public static String getFileFromUri(Context context, Uri uri) {
if (uri == null) {
return null;
}
switch (uri.getScheme()) {
case ContentResolver.SCHEME_CONTENT:
//Android7.0之后的uri content:// URI
return getFilePathFromContentUri(context, uri);
case ContentResolver.SCHEME_FILE:
default:
//Android7.0之前的uri file://
return new File(uri.getPath()).getAbsolutePath();
}
}
//
// 从uri获取path
//
// @param uri content://media/external/file/109009
// <p>
// FileProvider适配
// content://com.tencent.mobileqq.fileprovider/external_files/storage/emulated/0/Tencent/QQfile_recv/
// content://com.tencent.mm.external.fileprovider/external/tencent/MicroMsg/Download/
//
private static String getFilePathFromContentUri(Context context, Uri uri) {
if (null == uri) return null;
String data = null;
String[] filePathColumn = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DISPLAY_NAME};
Cursor cursor = context.getContentResolver().query(uri, filePathColumn, null, null, null);
if (null != cursor) {
if (cursor.moveToFirst()) {
int index = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
if (index > -1) {
data = cursor.getString(index);
} else {
int nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
String fileName = cursor.getString(nameIndex);
data = getPathFromInputStreamUri(context, uri, fileName);
}
}
cursor.close();
}
return data;
}
//
// 用流拷贝文件一份到自己APP私有目录下
//
// @param context
// @param uri
// @param fileName
//
private static String getPathFromInputStreamUri(Context context, Uri uri, String fileName) {
InputStream inputStream = null;
String filePath = null;
if (uri.getAuthority() != null) {
try {
inputStream = context.getContentResolver().openInputStream(uri);
File file = createTemporalFileFrom(context, inputStream, fileName);
filePath = file.getPath();
} catch (Exception e) {
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Exception e) {
}
}
}
return filePath;
}
private static File createTemporalFileFrom(Context context, InputStream inputStream, String fileName)
throws IOException {
File targetFile = null;
if (inputStream != null) {
int read;
byte[] buffer = new byte[8 * 1024];
//自己定义拷贝文件路径
targetFile = new File(context.getExternalCacheDir(), fileName);
if (targetFile.exists()) {
targetFile.delete();
}
OutputStream outputStream = new FileOutputStream(targetFile);
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
outputStream.flush();
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return targetFile;
}
}

View File

@@ -0,0 +1,38 @@
package cc.winboll.studio.libapputils.views;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/01/03 11:05:45
* @Describe 简单网页视图类
*/
import android.content.Context;
import android.util.AttributeSet;
import android.webkit.WebSettings;
import android.webkit.WebView;
public class SimpleWebView extends WebView {
public static final String TAG = "SimpleWebView";
public SimpleWebView(Context context) {
super(context);
initWebView();
}
public SimpleWebView(Context context, AttributeSet attrs) {
super(context, attrs);
initWebView();
}
public SimpleWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initWebView();
}
private void initWebView() {
// 获取WebView的设置对象
WebSettings webSettings = getSettings();
// 启用JavaScript
webSettings.setJavaScriptEnabled(true);
}
}

View File

@@ -0,0 +1,66 @@
package cc.winboll.studio.libapputils.views;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/12/19 13:49:14
* @Describe 把字符串转化为二维码的视图
*/
import cc.winboll.studio.libapputils.R;
import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import cc.winboll.studio.libapputils.utils.QRCodeGenerator;
import com.journeyapps.barcodescanner.DecoratedBarcodeView;
public class StringToQrCodeView extends LinearLayout {
static String TAG = "StringToQrCodeView";
Context mContext;
TextView mTextView;
ImageView mImageView;
private static final int REQUEST_CAMERA_PERMISSION = 1;
private DecoratedBarcodeView barcodeView;
public StringToQrCodeView(Context context) {
super(context);
initView(context);
}
public StringToQrCodeView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public StringToQrCodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
public StringToQrCodeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView(context);
}
void initView(Context context) {
mContext = context;
View view = inflate(context, R.layout.view_string2qrcode, null);
mTextView = view.findViewById(R.id.viewstring2qrcodeTextView1);
mImageView = view.findViewById(R.id.viewstring2qrcodeImageView1);
addView(view);
stringToQrCode("Hello, World!");
}
public void stringToQrCode(String text) {
Drawable drawable = new BitmapDrawable(getResources(), QRCodeGenerator.generateQRCodeImage(text, 300, 300));
mTextView.setText(text);
mImageView.setBackground(drawable);
}
}

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 阴影部分 -->
<!-- 个人觉得更形象的表达top代表下边的阴影高度left代表右边的阴影宽度。其实也就是相对应的offsetsolid中的颜色是阴影的颜色也可以设置角度等等 -->
<item
android:left="2dp"
android:top="2dp"
android:right="2dp"
android:bottom="2dp">
<shape android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="#0F000000"
android:startColor="#0F000000" />
<corners
android:bottomLeftRadius="6dip"
android:bottomRightRadius="6dip"
android:topLeftRadius="6dip"
android:topRightRadius="6dip" />
</shape>
</item>
<!-- 背景部分 -->
<!-- 形象的表达bottom代表背景部分在上边缘超出阴影的高度right代表背景部分在左边超出阴影的宽度相对应的offset -->
<item
android:left="3dp"
android:top="3dp"
android:right="3dp"
android:bottom="5dp">
<shape android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="@color/colorAccent"
android:startColor="@color/colorAccent" />
<corners
android:bottomLeftRadius="6dip"
android:bottomRightRadius="6dip"
android:topLeftRadius="6dip"
android:topRightRadius="6dip" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#ff000000"
android:pathData="M4,1C2.89,1 2,1.89 2,3V7C2,8.11 2.89,9 4,9H1V11H13V9H10C11.11,9 12,8.11 12,7V3C12,1.89 11.11,1 10,1H4M4,3H10V7H4V3M3,12V14H5V12H3M14,13C12.89,13 12,13.89 12,15V19C12,20.11 12.89,21 14,21H11V23H23V21H20C21.11,21 22,20.11 22,19V15C22,13.89 21.11,13 20,13H14M3,15V17H5V15H3M14,15H20V19H14V15M3,18V20H5V18H3M6,18V20H8V18H6M9,18V20H11V18H9Z"/>
</vector>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#ff000000"
android:pathData="M4,1C2.89,1 2,1.89 2,3V7C2,8.11 2.89,9 4,9H1V11H13V9H10C11.11,9 12,8.11 12,7V3C12,1.89 11.11,1 10,1H4M4,3H10V7H4V3M14,13C12.89,13 12,13.89 12,15V19C12,20.11 12.89,21 14,21H11V23H23V21H20C21.11,21 22,20.11 22,19V15C22,13.89 21.11,13 20,13H14M3.88,13.46L2.46,14.88L4.59,17L2.46,19.12L3.88,20.54L6,18.41L8.12,20.54L9.54,19.12L7.41,17L9.54,14.88L8.12,13.46L6,15.59L3.88,13.46M14,15H20V19H14V15Z"/>
</vector>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#ff000000"
android:pathData="M22,6C22,4.9 21.1,4 20,4H4C2.9,4 2,4.9 2,6V18C2,19.1 2.9,20 4,20H20C21.1,20 22,19.1 22,18V6M20,6L12,11L4,6H20M20,18H4V8L12,13L20,8V18Z"/>
</vector>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#ff000000"
android:pathData="M24,7H22V13H24V7M24,15H22V17H24V15M20,6C20,4.9 19.1,4 18,4H2C0.9,4 0,4.9 0,6V18C0,19.1 0.9,20 2,20H18C19.1,20 20,19.1 20,18V6M18,6L10,11L2,6H18M18,18H2V8L10,13L18,8V18Z"/>
</vector>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:clickable="true">
<item
android:width="256dp"
android:height="256dp"
android:left="0dp"
android:top="0dp"
android:right="0dp"
android:bottom="0dp"
android:drawable="@drawable/winboll_logo">
</item>
</layer-list>

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="@color/colorPrimary"
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,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16.61,15.15C16.15,15.15 15.77,14.78 15.77,14.32S16.15,13.5 16.61,13.5H16.61C17.07,13.5 17.45,13.86 17.45,14.32C17.45,14.78 17.07,15.15 16.61,15.15M7.41,15.15C6.95,15.15 6.57,14.78 6.57,14.32C6.57,13.86 6.95,13.5 7.41,13.5H7.41C7.87,13.5 8.24,13.86 8.24,14.32C8.24,14.78 7.87,15.15 7.41,15.15M16.91,10.14L18.58,7.26C18.67,7.09 18.61,6.88 18.45,6.79C18.28,6.69 18.07,6.75 18,6.92L16.29,9.83C14.95,9.22 13.5,8.9 12,8.91C10.47,8.91 9,9.24 7.73,9.82L6.04,6.91C5.95,6.74 5.74,6.68 5.57,6.78C5.4,6.87 5.35,7.08 5.44,7.25L7.1,10.13C4.25,11.69 2.29,14.58 2,18H22C21.72,14.59 19.77,11.7 16.91,10.14H16.91Z"/>
</vector>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:clickable="true">
<item
android:width="256dp"
android:height="256dp"
android:left="0dp"
android:top="0dp"
android:right="0dp"
android:bottom="0dp"
android:drawable="@drawable/winboll_logo">
</item>
</layer-list>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:clickable="true">
<item android:drawable="@drawable/ic_launcher_background"/>
<item
android:left="0dp"
android:top="0dp"
android:right="0dp"
android:bottom="0dp"
android:drawable="@drawable/winboll_logo"/>
</layer-list>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="180"
android:endColor="#FFFFFFFF"
android:startColor="#FFFFFFFF"
android:type="linear" />
<corners android:radius="10dp" />
</shape>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="1dp"
android:color="#000000" /> <!-- 这里可调整边框宽度和颜色 -->
<solid android:color="@android:color/transparent" />
</shape>

View File

@@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#FF1E9B54"
android:strokeColor="#FFF8E733"
android:strokeWidth="20.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M254.63 35.45C374.95 35.45 473.38 133.89 473.38 254.2 473.38 374.51 374.95 472.95 254.63 472.95 134.32 472.95 35.88 374.51 35.88 254.2 35.88 133.89 134.32 35.45 254.63 35.45"/>
<path
android:fillColor="#FF000000"
android:strokeColor="#FF000000"
android:strokeWidth="1.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M257.28 361.25C266.56 361.25 274.14 368.84 274.14 378.11 274.14 387.39 266.56 394.98 257.28 394.98 248.01 394.98 240.42 387.39 240.42 378.11 240.42 368.84 248.01 361.25 257.28 361.25"/>
<path
android:fillColor="#00000000"
android:strokeColor="#FF000000"
android:strokeWidth="30.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M182.16 214.09C181.42 199.71 182.42 177.87 207.64 155.49 213.64 150.16 220.13 146.12 226.28 143.08 238.64 136.97 249.62 134.91 252.55 134.56 252.7 134.54 252.83 134.53 252.94 134.52 253.05 134.51 253.14 134.5 253.2 134.5 255.01 134.48 294.9 136.66 313.05 160.43 332.29 185.63 344.82 221.3 300.07 263.56 263.08 298.49 258.36 318 258.54 317.72"/>
</vector>

View File

@@ -0,0 +1,48 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#FF1E9B54"
android:strokeColor="#FFF8E733"
android:strokeWidth="20.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M254.63 35.45C374.95 35.45 473.38 133.89 473.38 254.2 473.38 374.51 374.95 472.95 254.63 472.95 134.32 472.95 35.88 374.51 35.88 254.2 35.88 133.89 134.32 35.45 254.63 35.45"/>
<path
android:fillColor="#FFFFFFFF"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="1.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M257.28 361.25C266.56 361.25 274.14 368.84 274.14 378.11 274.14 387.39 266.56 394.98 257.28 394.98 248.01 394.98 240.42 387.39 240.42 378.11 240.42 368.84 248.01 361.25 257.28 361.25"/>
<path
android:fillColor="#00000000"
android:strokeColor="#FF000000"
android:strokeWidth="30.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M182.16 214.09C181.42 199.71 182.42 177.87 207.64 155.49 213.64 150.16 220.13 146.12 226.28 143.08 238.64 136.97 249.62 134.91 252.55 134.56 252.7 134.54 252.83 134.53 252.94 134.52 253.05 134.51 253.14 134.5 253.2 134.5 255.01 134.48 294.9 136.66 313.05 160.43 332.29 185.63 344.82 221.3 300.07 263.56 263.08 298.49 258.36 318 258.54 317.72"/>
<path
android:fillColor="#00000000"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="30.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M103.77 307.45C103.02 293.07 104.03 271.24 129.24 248.85 135.25 243.52 141.74 239.48 147.89 236.44 160.24 230.34 171.23 228.28 174.15 227.92 174.31 227.9 174.44 227.89 174.55 227.88 174.66 227.87 174.75 227.86 174.81 227.86 176.62 227.85 216.5 230.02 234.65 253.79 253.9 278.99 266.43 314.66 221.67 356.93 184.69 391.85 179.97 411.36 180.15 411.08"/>
<path
android:fillColor="#00000000"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="30.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M248.17 309.83C247.43 295.45 248.43 273.62 273.64 251.23 279.65 245.9 286.14 241.86 292.29 238.82 304.65 232.72 315.63 230.65 318.55 230.3 318.71 230.28 318.84 230.27 318.95 230.26 319.06 230.25 319.15 230.24 319.21 230.24 321.02 230.22 360.9 232.4 379.06 256.17 398.3 281.37 410.83 317.04 366.08 359.31 329.09 394.23 324.37 413.74 324.55 413.46"/>
<path
android:fillColor="#00000000"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="30.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M182.16 214.09C181.42 199.71 182.42 177.87 207.64 155.49 213.64 150.16 220.13 146.12 226.28 143.08 238.64 136.97 249.62 134.91 252.55 134.56 252.7 134.54 252.83 134.53 252.94 134.52 253.05 134.51 253.14 134.5 253.2 134.5 255.01 134.48 294.9 136.66 313.05 160.43 332.29 185.63 344.82 221.3 300.07 263.56 263.08 298.49 258.36 318 258.54 317.72"/>
</vector>

View File

@@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#FF1E9B54"
android:strokeColor="#FFF8E733"
android:strokeWidth="20.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M254.63 35.45C374.95 35.45 473.38 133.89 473.38 254.2 473.38 374.51 374.95 472.95 254.63 472.95 134.32 472.95 35.88 374.51 35.88 254.2 35.88 133.89 134.32 35.45 254.63 35.45"/>
<path
android:fillColor="#FFFFFFFF"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="1.0"
android:strokeLineCap="round"
android:strokeMiterLimit="10"
android:pathData="M257.28 361.25C266.56 361.25 274.14 368.84 274.14 378.11 274.14 387.39 266.56 394.98 257.28 394.98 248.01 394.98 240.42 387.39 240.42 378.11 240.42 368.84 248.01 361.25 257.28 361.25"/>
</vector>

View File

@@ -0,0 +1,11 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<cc.winboll.studio.libappbase.LogView
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:id="@+id/logview"/>
</LinearLayout>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/activityunittestLinearLayout1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="UnitTest"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/activityunittestLinearLayout2">
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.webkit.WebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/viewadsWebView1"/>
</RelativeLayout>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="QRCode UnitTest"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="MessageText"
android:textColor="#FFFF0000"
android:id="@+id/viewstring2qrcodeTextView1"/>
<ImageView
android:orientation="vertical"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#FF099EF2"
android:id="@+id/viewstring2qrcodeImageView1"/>
</LinearLayout>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!--<item android:title="@string/app_theme">
<menu>-->
<!-- 定义一组单选按钮 -->
<!-- checkableBehavior的可选值由三个single设置为单选all为多选none为普通选项 -->
<!-- <group android:checkableBehavior="single">
<item android:id="@+id/app_defaulttheme" android:title="@string/app_defaulttheme"/>
<item android:id="@+id/app_skytheme" android:title="@string/app_skytheme"/>
<item android:id="@+id/app_goldentheme" android:title="@string/app_goldentheme"/>
</group>
</menu>
</item>-->
<item android:title="DebugTools">
<menu>
<item
android:id="@+id/item_testcrashreport"
android:title="Test Application Crash Report"/>
<item
android:id="@+id/item_unittest"
android:title="UnitTest"/>
<item
android:id="@+id/item_log"
android:title="APPLOG"/>
<item
android:id="@+id/item_info"
android:title="Info"/>
<item
android:id="@+id/item_exitdebug"
android:title="ExitDebug"/>
</menu>
</item>
</menu>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/item_help"
android:title="HELP"
android:icon="@drawable/winboll_help"/>
</menu>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/item_exit"
android:title="EXIT"
android:icon="@drawable/winboll_point"/>
<item
android:id="@+id/item_about"
android:title="About"
android:icon="@drawable/winboll_logo"/>
</menu>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
</style>
</resources>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="enum_loglevel_array">
<item>Off</item>
<item>Error</item>
<item>Warn</item>
<item>Info</item>
<item>Debug</item>
<item>Verbose</item>
</array>
</resources>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AboutView">
<attr name="app_name" format="string" />
<attr name="app_apkfoldername" format="string" />
<attr name="app_apkname" format="string" />
<attr name="app_gitname" format="string" />
<attr name="app_gitowner" format="string" />
<attr name="app_gitappbranch" format="string" />
<attr name="app_gitappsubprojectfolder" format="string" />
<attr name="appdescription" format="string" />
<attr name="appicon" format="reference" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#FF196ABC</color>
<color name="colorPrimaryDark">#FF002B57</color>
<color name="colorAccent">#FF80BFFF</color>
</resources>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="lib_name">libapputils</string>
<string name="app_normal">Click here is switch to Normal APP</string>
<string name="app_debug">Click here is switch to APP DEBUG</string>
<string name="gitea_home">GITEA HOME</string>
<string name="app_update">APP UPDATE</string>
<string name="hello_world">Hello world!</string>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="UtilsTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
</style>
</resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.8.0.13</domain>
</domain-config>
</network-security-config>