mirror of
http://gitea.winboll.cc/Studio/WinBoLL.git
synced 2026-06-29 12:09:49 +08:00
Compare commits
58 Commits
appbase-v1
...
appbase-v1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e234436853 | ||
| 79d49fbc10 | |||
| 406b15ccc5 | |||
| bdefa7dec9 | |||
|
|
b931a1e0bd | ||
|
|
60afeabed0 | ||
| cbfebb921a | |||
| 208ced7af5 | |||
| bf9a89dc7a | |||
| b28054cf57 | |||
| 102aae8e66 | |||
| 9e52dc29a7 | |||
| dc622003bd | |||
| 91841962f1 | |||
|
|
ab4cef21f0 | ||
| 9071d3abd0 | |||
| d34fd0368f | |||
|
|
5185ecee3c | ||
|
|
7efd1b5f5c | ||
|
|
61933ae75b | ||
|
|
463585988d | ||
| 2754a2ad7c | |||
| da0fb646ab | |||
| 77d278501a | |||
| d2cd5f189f | |||
| 8876896cbc | |||
| d6fde41a8c | |||
| 28e6a8ee78 | |||
| 7d872fd14c | |||
| d6fab2133f | |||
| 45821b8daa | |||
| edd312a525 | |||
| aec680e36e | |||
| 1c6f7783e5 | |||
|
|
193011a80d | ||
|
|
eb3d8f4806 | ||
| aa1b701c8b | |||
| fc20bd56b4 | |||
| e92538850f | |||
| 81b7af0ec4 | |||
| e2b4bddb61 | |||
| cbca61ad84 | |||
| 28bc3a86e3 | |||
| 79f7f682b3 | |||
| 8fa09a9f99 | |||
| 555c5deef9 | |||
| 3707891e0b | |||
| 0c9c6c9fd4 | |||
| be3d042ade | |||
|
|
33dc49267e | ||
| e3166b639e | |||
| 3d26bbe090 | |||
| cd375cefc5 | |||
| 025c095bcd | |||
| c88a0a52a8 | |||
| dc4eeefa55 | |||
| c7d79e160b | |||
|
|
771f591a3a |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -101,4 +101,5 @@ lint-results.html
|
||||
#/gradle.properties
|
||||
|
||||
## APPBase 项目配置
|
||||
|
||||
aes/
|
||||
libaes/
|
||||
|
||||
145
.winboll/bashMergeProjects-to-Projects_Keeper_Tag.sh
Normal file
145
.winboll/bashMergeProjects-to-Projects_Keeper_Tag.sh
Normal file
@@ -0,0 +1,145 @@
|
||||
#!/system/bin/sh
|
||||
## 逻辑:按时间取最新标签 → 拉取该标签目录合并
|
||||
|
||||
# 按创建时间取模块最新标签(最新打的标签排最后)
|
||||
get_latest_module_tag(){
|
||||
local mod=$1
|
||||
git for-each-ref --sort=-creatordate --format='%(refname)' refs/tags/${mod}-* \
|
||||
| grep -v '\^{}' \
|
||||
| head -1 \
|
||||
| sed 's/refs\/tags\///'
|
||||
}
|
||||
|
||||
# 通过标签获取commit
|
||||
get_commit_from_tag(){
|
||||
local tag=$1
|
||||
git rev-parse --short "${tag}^{commit}"
|
||||
}
|
||||
|
||||
# 工作目录
|
||||
TARGET_DIR="/sdcard/AppProjects/Projects_Keeper_Tag"
|
||||
echo "进入目录:${TARGET_DIR}"
|
||||
cd "${TARGET_DIR}" || exit 1
|
||||
|
||||
# 同步远程
|
||||
echo "========================================"
|
||||
echo "同步远程分支与全部版本标签"
|
||||
echo "========================================"
|
||||
git fetch origin --prune
|
||||
git fetch origin --tags
|
||||
echo "同步完成"
|
||||
echo ""
|
||||
|
||||
# 校验目标分支
|
||||
NOW_BRANCH=$(git symbolic-ref --short HEAD)
|
||||
TARGET_BRANCH="projects_keeper_tag"
|
||||
if [ "${NOW_BRANCH}" != "${TARGET_BRANCH}" ];then
|
||||
echo "错误:请先切换到 ${TARGET_BRANCH} 分支"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 目录结构校验
|
||||
MERGE_OBJECTS_LIST=(
|
||||
.git
|
||||
.gitignore
|
||||
.gitmodules
|
||||
.winboll
|
||||
GenKeyStore
|
||||
LICENSE
|
||||
LICENSE-Private-Demo
|
||||
LICENSE-Private-Demo_docs
|
||||
README.md
|
||||
aes
|
||||
appbase
|
||||
autonfc
|
||||
build.gradle
|
||||
contacts
|
||||
debugtemp
|
||||
gallery
|
||||
gpsrelaysentinel
|
||||
gradle
|
||||
gradle.properties-android-demo
|
||||
gradle.properties-androidx-demo
|
||||
gradlew
|
||||
libaes
|
||||
libappbase
|
||||
libdebugtemp
|
||||
libgpsrelaysentinel
|
||||
libwinboll
|
||||
local.properties-demo
|
||||
mymessagemanager
|
||||
positions
|
||||
powerbell
|
||||
settings.gradle-demo
|
||||
winboll
|
||||
winboll.properties-demo
|
||||
)
|
||||
|
||||
REAL_ITEMS=()
|
||||
while IFS= read -r line; do
|
||||
[[ $line != "." && $line != ".." ]] && REAL_ITEMS+=("$line")
|
||||
done < <(ls -a)
|
||||
|
||||
check_diff(){
|
||||
local miss=() extra=()
|
||||
for i in "${MERGE_OBJECTS_LIST[@]}";do
|
||||
[[ ! " ${REAL_ITEMS[@]} " =~ " ${i} " ]] && miss+=("$i")
|
||||
done
|
||||
for i in "${REAL_ITEMS[@]}";do
|
||||
[[ ! " ${MERGE_OBJECTS_LIST[@]} " =~ " ${i} " ]] && extra+=("$i")
|
||||
done
|
||||
if [[ ${#miss[@]} -gt 0 || ${#extra[@]} -gt 0 ]];then
|
||||
echo "本地目录结构不一致,终止运行"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
check_diff
|
||||
|
||||
echo -e "#@@@ 按时间获取最新标签合并模块源码 @@@#"
|
||||
|
||||
# 应用型模块
|
||||
MERGE_APP_PROJECT_LIST=(DemoAPP)
|
||||
echo -e "---------- 应用型模块 ----------"
|
||||
for name in "${MERGE_APP_PROJECT_LIST[@]}";do
|
||||
low_name=$(echo "$name" | tr 'A-Z' 'a-z')
|
||||
tag=$(get_latest_module_tag "${low_name}")
|
||||
if [[ -z "${tag}" ]];then
|
||||
echo "跳过 ${low_name}:无远程标签"
|
||||
continue
|
||||
fi
|
||||
commit=$(get_commit_from_tag "${tag}")
|
||||
if [[ -z "${commit}" ]];then
|
||||
echo "跳过 ${low_name}:标签无有效提交点"
|
||||
continue
|
||||
fi
|
||||
echo "模块:${low_name} 最新时间标签:${tag} 提交ID:${commit}"
|
||||
# 强制拉取覆盖
|
||||
git checkout -f "${tag}" -- "${low_name}"
|
||||
git add "${low_name}"
|
||||
git commit -m "合并模块${name} 同步最新时间标签${tag}"
|
||||
done
|
||||
|
||||
# 类库模块
|
||||
MERGE_LIB_PROJECT_LIST=(WinBoLL APPBase AES)
|
||||
echo -e "---------- 类库模块 ----------"
|
||||
for name in "${MERGE_LIB_PROJECT_LIST[@]}";do
|
||||
low_name=$(echo "$name" | tr 'A-Z' 'a-z')
|
||||
tag=$(get_latest_module_tag "${low_name}")
|
||||
if [[ -z "${tag}" ]];then
|
||||
echo "跳过 ${low_name}:无远程标签"
|
||||
continue
|
||||
fi
|
||||
commit=$(get_commit_from_tag "${tag}")
|
||||
if [[ -z "${commit}" ]];then
|
||||
echo "跳过 ${low_name}:标签无有效提交点"
|
||||
continue
|
||||
fi
|
||||
echo "模块:${low_name} 最新时间标签:${tag} 提交ID:${commit}"
|
||||
git checkout -f "${tag}" -- "${low_name}" "lib${low_name}"
|
||||
git add "${low_name}" "lib${low_name}"
|
||||
git commit -m "合并模块${name} 同步最新时间标签${tag}"
|
||||
done
|
||||
|
||||
echo "全部模块合并执行完毕"
|
||||
echo "执行推送:git push"
|
||||
git push
|
||||
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Wed May 20 16:12:13 HKT 2026
|
||||
stageCount=21
|
||||
#Wed Jun 03 06:48:01 HKT 2026
|
||||
stageCount=25
|
||||
libraryProject=libappbase
|
||||
baseVersion=15.20
|
||||
publishVersion=15.20.20
|
||||
publishVersion=15.20.24
|
||||
buildCount=0
|
||||
baseBetaVersion=15.20.21
|
||||
baseBetaVersion=15.20.25
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package cc.winboll.studio.appbase;
|
||||
|
||||
import cc.winboll.studio.libappbase.CrashHandler;
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.libappbase.BuildConfig;
|
||||
import cc.winboll.studio.libappbase.utils.CrashHandleNotifyUtils;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
@@ -21,10 +24,27 @@ public class App extends GlobalApplication {
|
||||
*/
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
// 初始化 Toast 工具类(传入应用全局上下文,确保 Toast 可在任意地方调用)
|
||||
ToastUtils.init(getApplicationContext());
|
||||
try {
|
||||
super.onCreate();
|
||||
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
|
||||
getString(i);
|
||||
}
|
||||
|
||||
// 初始化 Toast 工具类(传入应用全局上下文,确保 Toast 可在任意地方调用)
|
||||
ToastUtils.init(getApplicationContext());
|
||||
} catch (Throwable e) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
pw.close();
|
||||
String stackTraceStr = sw.toString();
|
||||
CrashHandleNotifyUtils.handleUncaughtException(
|
||||
this,
|
||||
getPackageName(),
|
||||
stackTraceStr,
|
||||
CrashHandler.CrashActivity.class
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Wed May 20 16:12:13 HKT 2026
|
||||
stageCount=21
|
||||
#Wed Jun 03 06:48:01 HKT 2026
|
||||
stageCount=25
|
||||
libraryProject=libappbase
|
||||
baseVersion=15.20
|
||||
publishVersion=15.20.20
|
||||
publishVersion=15.20.24
|
||||
buildCount=0
|
||||
baseBetaVersion=15.20.21
|
||||
baseBetaVersion=15.20.25
|
||||
|
||||
@@ -263,7 +263,7 @@ public final class CrashHandler {
|
||||
setContentView(contentView);
|
||||
|
||||
getActionBar().setTitle(TITTLE);
|
||||
getActionBar().setSubtitle(GlobalApplication.class.getSimpleName() + " Error");
|
||||
getActionBar().setSubtitle(GlobalApplication.getAppName(getApplicationContext()) + " Error");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,10 @@ import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.util.Log;
|
||||
import cc.winboll.studio.libappbase.utils.CrashHandleNotifyUtils;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
@@ -125,17 +129,32 @@ public class GlobalApplication extends Application {
|
||||
*/
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
// 初始化单例实例(确保在所有初始化操作前完成)
|
||||
sInstance = this;
|
||||
try {
|
||||
super.onCreate();
|
||||
|
||||
// 初始化单例实例(确保在所有初始化操作前完成)
|
||||
sInstance = this;
|
||||
|
||||
restoreDebugStatus();
|
||||
// 初始化基础组件(日志、崩溃处理、Toast)
|
||||
initCoreComponents();
|
||||
// 初始化服务器地址(从 SP 读取到内存,提高后续访问效率)
|
||||
initWinbollHost();
|
||||
restoreDebugStatus();
|
||||
// 初始化基础组件(日志、崩溃处理、Toast)
|
||||
initCoreComponents();
|
||||
// 初始化服务器地址(从 SP 读取到内存,提高后续访问效率)
|
||||
initWinbollHost();
|
||||
|
||||
LogUtils.d(TAG, "GlobalApplication 初始化完成,单例实例已创建");
|
||||
LogUtils.d(TAG, "GlobalApplication 初始化完成,单例实例已创建");
|
||||
} catch (Throwable e) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
pw.close();
|
||||
String stackTraceStr = sw.toString();
|
||||
CrashHandleNotifyUtils.handleUncaughtException(
|
||||
this,
|
||||
getPackageName(),
|
||||
stackTraceStr,
|
||||
CrashHandler.CrashActivity.class
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,7 +209,7 @@ public class GlobalApplication extends Application {
|
||||
*/
|
||||
public static String getAppName(Context context) {
|
||||
if (context == null) {
|
||||
LogUtils.w(TAG, "getAppName: 上下文为空,返回 null");
|
||||
Log.w(TAG, "getAppName: 上下文为空,返回 null");
|
||||
return null;
|
||||
}
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
@@ -206,8 +225,7 @@ public class GlobalApplication extends Application {
|
||||
return appName;
|
||||
} catch (NameNotFoundException e) {
|
||||
// 包名不存在(理论上不会发生,捕获异常避免崩溃)
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
//LogUtils.e(TAG, "获取应用名称失败:包名不存在", e);
|
||||
Log.e(TAG, "获取应用名称失败:包名不存在", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package cc.winboll.studio.libappbase.views;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
@@ -12,6 +14,7 @@ import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.R;
|
||||
@@ -74,12 +77,12 @@ public class AboutView extends LinearLayout {
|
||||
private EditText metDevUserPassword;
|
||||
|
||||
// ===================================== 页面视图控件 =====================================
|
||||
private DebugSwitchImageView ivAppIcon;
|
||||
private DebugSwitchInfoImageView ivAppIcon;
|
||||
private TextView tvAppNameVersion;
|
||||
private TextView tvAppDesc;
|
||||
private LinearLayout llFunctionContainer;
|
||||
private ImageButton ibSebugStepOver;
|
||||
private ImageButton ibSigngetDialog;
|
||||
private ImageButton ibDebugUnlock;
|
||||
private ImageButton ibWinBoLLHostDialog;
|
||||
|
||||
// ===================================== 构造方法(按参数从少到多排序) =====================================
|
||||
@@ -193,12 +196,12 @@ public class AboutView extends LinearLayout {
|
||||
llFunctionContainer = findViewById(R.id.ll_function_container);
|
||||
// 功能按钮绑定
|
||||
ibSebugStepOver = findViewById(R.id.ib_debug_step_over);
|
||||
ibSigngetDialog = findViewById(R.id.ib_signgetdialog);
|
||||
ibDebugUnlock = findViewById(R.id.ib_debug_unlock);
|
||||
ibWinBoLLHostDialog = findViewById(R.id.ib_winbollhostdialog);
|
||||
|
||||
// 调试按钮统一只在调试模式显示
|
||||
ibWinBoLLHostDialog.setVisibility(GlobalApplication.isDebugging() ? View.VISIBLE : View.GONE);
|
||||
//ibSigngetDialog.setVisibility(GlobalApplication.isDebugging() ? View.VISIBLE : View.GONE);
|
||||
//ibDebugUnlock.setVisibility(GlobalApplication.isDebugging() ? View.VISIBLE : View.GONE);
|
||||
ibSebugStepOver.setVisibility(GlobalApplication.isDebugging() ? View.VISIBLE : View.GONE);
|
||||
|
||||
// 绑定按钮点击事件
|
||||
@@ -310,6 +313,47 @@ public class AboutView extends LinearLayout {
|
||||
LogUtils.d(TAG, "initAboutPageView():视图组装完成,功能项加载完毕");
|
||||
}
|
||||
|
||||
// ===================================== 调试解锁弹窗 =====================================
|
||||
private void showDebugUnlockDialog() {
|
||||
final AlertDialog dialog = new AlertDialog.Builder(mContext).create();
|
||||
dialog.setTitle("应用调试解锁");
|
||||
dialog.setCanceledOnTouchOutside(true);
|
||||
|
||||
final EditText etToken = new EditText(mContext);
|
||||
etToken.setHint("请输入调试Token");
|
||||
dialog.setView(etToken);
|
||||
|
||||
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "调试解锁", (DialogInterface.OnClickListener) null);
|
||||
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "关闭", (DialogInterface.OnClickListener) null);
|
||||
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface d) {
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String inputToken = etToken.getText().toString().trim();
|
||||
String savedToken = DebugSwitchInfoImageView.getDebugToken();
|
||||
if (savedToken != null && savedToken.equals(inputToken)) {
|
||||
GlobalApplication.setIsDebugging(true);
|
||||
GlobalApplication.saveDebugStatus(GlobalApplication.getInstance());
|
||||
Toast.makeText(mContext, "调试解锁成功,重启应用后生效", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(mContext, "调试Token不匹配", Toast.LENGTH_SHORT).show();
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
});
|
||||
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
// ===================================== 内部工具/事件方法 =====================================
|
||||
/**
|
||||
* 绑定功能按钮点击事件,处理正版校验、调试地址配置弹窗唤起
|
||||
@@ -335,6 +379,15 @@ public class AboutView extends LinearLayout {
|
||||
new DebugHostDialog(mContext).show();
|
||||
}
|
||||
});
|
||||
|
||||
// 应用调试解锁按钮
|
||||
ibDebugUnlock.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "ibDebugUnlock onClick:弹出调试解锁对话框");
|
||||
showDebugUnlockDialog();
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "setBtnClickListener():功能按钮点击事件绑定完成");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package cc.winboll.studio.libappbase.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/04/06 19:32
|
||||
* @Describe 具有调试模式切换功能的应用Logo控件,连续点击10次弹出提示
|
||||
*/
|
||||
public class DebugSwitchImageView extends ImageView {
|
||||
|
||||
public static final String TAG = "DebugSwitchImageView";
|
||||
|
||||
// 连续点击计数
|
||||
private int mClickCount = 0;
|
||||
// 目标点击次数
|
||||
private static final int TARGET_CLICK_COUNT = 10;
|
||||
|
||||
public DebugSwitchImageView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public DebugSwitchImageView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public DebugSwitchImageView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
public DebugSwitchImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mClickCount++;
|
||||
if (mClickCount == TARGET_CLICK_COUNT) {
|
||||
// 达到10次,弹出Toast
|
||||
Toast.makeText(getContext(), "连续点击已达到10次,现在开启应用调试功能。", Toast.LENGTH_SHORT).show();
|
||||
GlobalApplication.setIsDebugging(true);
|
||||
GlobalApplication.saveDebugStatus(GlobalApplication.getInstance());
|
||||
// 重置计数,可再次触发
|
||||
mClickCount = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
package cc.winboll.studio.libappbase.views;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import java.util.UUID;
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/04/06 19:32
|
||||
* @Describe 应用Logo控件,连续点击6次弹出调试Token对话框,支持复制与重置
|
||||
*/
|
||||
public class DebugSwitchInfoImageView extends ImageView {
|
||||
|
||||
public static final String TAG = "DebugSwitchInfoImageView";
|
||||
|
||||
// 连续点击计数
|
||||
private int mClickCount = 0;
|
||||
// 目标点击次数
|
||||
private static final int TARGET_CLICK_COUNT = 7;
|
||||
|
||||
private static String mDebugToken = null;
|
||||
private static final String SP_DEBUG_TOKEN = "debug_token_prefs";
|
||||
private static final String KEY_DEBUG_TOKEN = "debug_token";
|
||||
|
||||
public static String getDebugToken() {
|
||||
if (mDebugToken != null) {
|
||||
return mDebugToken;
|
||||
}
|
||||
Context context = GlobalApplication.getInstance();
|
||||
if (context != null) {
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_DEBUG_TOKEN, Context.MODE_PRIVATE);
|
||||
mDebugToken = sp.getString(KEY_DEBUG_TOKEN, null);
|
||||
if (mDebugToken == null) {
|
||||
mDebugToken = UUID.randomUUID().toString();
|
||||
sp.edit().putString(KEY_DEBUG_TOKEN, mDebugToken).apply();
|
||||
}
|
||||
}
|
||||
return mDebugToken;
|
||||
}
|
||||
|
||||
public static void resetDebugToken() {
|
||||
Context context = GlobalApplication.getInstance();
|
||||
if (context != null) {
|
||||
mDebugToken = UUID.randomUUID().toString();
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_DEBUG_TOKEN, Context.MODE_PRIVATE);
|
||||
sp.edit().putString(KEY_DEBUG_TOKEN, mDebugToken).apply();
|
||||
}
|
||||
}
|
||||
|
||||
private void showDebugTokenDialog() {
|
||||
final AlertDialog dialog = new AlertDialog.Builder(getContext()).create();
|
||||
dialog.setTitle("调试Token");
|
||||
dialog.setMessage(getDebugToken());
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "复制到剪贴板", (DialogInterface.OnClickListener) null);
|
||||
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, "重置", (DialogInterface.OnClickListener) null);
|
||||
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "关闭", (DialogInterface.OnClickListener) null);
|
||||
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface d) {
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ClipboardManager cm = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setPrimaryClip(ClipData.newPlainText("DebugToken", getDebugToken()));
|
||||
}
|
||||
});
|
||||
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
resetDebugToken();
|
||||
dialog.setMessage(getDebugToken());
|
||||
}
|
||||
});
|
||||
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public DebugSwitchInfoImageView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public DebugSwitchInfoImageView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public DebugSwitchInfoImageView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
public DebugSwitchInfoImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mClickCount++;
|
||||
if (mClickCount >= TARGET_CLICK_COUNT) {
|
||||
mClickCount = 0;
|
||||
showDebugTokenDialog();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<cc.winboll.studio.libappbase.views.DebugSwitchImageView
|
||||
<cc.winboll.studio.libappbase.views.DebugSwitchInfoImageView
|
||||
android:id="@+id/iv_app_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
@@ -81,7 +81,8 @@
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:src="@drawable/ic_key"
|
||||
android:id="@+id/ib_signgetdialog"
|
||||
android:id="@+id/ib_debug_unlock"
|
||||
android:contentDescription="应用调试解锁"
|
||||
android:scaleType="fitCenter"
|
||||
android:adjustViewBounds="true"
|
||||
android:background="@null"/>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<cc.winboll.studio.libappbase.views.DebugSwitchImageView
|
||||
<cc.winboll.studio.libappbase.views.DebugSwitchInfoImageView
|
||||
android:id="@+id/iv_app_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
@@ -81,7 +81,8 @@
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:src="@drawable/ic_key"
|
||||
android:id="@+id/ib_signgetdialog"
|
||||
android:id="@+id/ib_debug_unlock"
|
||||
android:contentDescription="应用调试解锁"
|
||||
android:scaleType="fitCenter"
|
||||
android:adjustViewBounds="true"
|
||||
android:background="@null"/>
|
||||
|
||||
@@ -1,5 +1,98 @@
|
||||
// AutoInstaller 项目编译设置
|
||||
//include ':autoinstaller'
|
||||
//rootProject.name = "autoinstaller"
|
||||
|
||||
// MJ 项目编译设置
|
||||
//include ':mj'
|
||||
//rootProject.name = "mj"
|
||||
|
||||
// PowerBell 项目编译设置
|
||||
//include ':powerbell'
|
||||
//rootProject.name = "powerbell"
|
||||
|
||||
// APPBase 项目编译设置
|
||||
include ':appbase'
|
||||
include ':libappbase'
|
||||
rootProject.name = "appbase"
|
||||
|
||||
// APPUtils 项目编译设置
|
||||
//include ':apputils'
|
||||
//include ':libapputils'
|
||||
//rootProject.name = "apputils"
|
||||
|
||||
// JC 项目编译设置
|
||||
//include ':jc'
|
||||
//include ':libjc'
|
||||
//rootProject.name = "jc"
|
||||
|
||||
// AES 项目编译设置
|
||||
//include ':aes'
|
||||
//include ':libaes'
|
||||
//rootProject.name = "aes"
|
||||
|
||||
// Contacts 项目编译设置
|
||||
//include ':contacts'
|
||||
//rootProject.name = "contacts"
|
||||
|
||||
// MyMessageManager 项目编译设置
|
||||
//include ':mymessagemanager'
|
||||
//rootProject.name = "mymessagemanager"
|
||||
|
||||
// TimeStamp 项目编译设置
|
||||
//include ':timestamp'
|
||||
//rootProject.name = "timestamp"
|
||||
|
||||
// AndroidDemo 项目编译设置
|
||||
//include ':androiddemo'
|
||||
//rootProject.name = "androiddemo"
|
||||
|
||||
// AndroidXDemo 项目编译设置
|
||||
//include ':androidxdemo'
|
||||
//rootProject.name = "androidxdemo"
|
||||
|
||||
// Ollama 项目编译设置
|
||||
//include ':ollama'
|
||||
//rootProject.name = "ollama"
|
||||
|
||||
// NumTable 项目编译设置
|
||||
//include ':numtable'
|
||||
//rootProject.name = "numtable"
|
||||
|
||||
// MidiPlayer 项目编译设置
|
||||
//include ':midiplayer'
|
||||
//rootProject.name = "midiplayer"
|
||||
|
||||
// WebPageSources 项目编译设置
|
||||
//include ':webpagesources'
|
||||
//rootProject.name = "webpagesources"
|
||||
|
||||
// Positions 项目编译设置
|
||||
//include ':positions'
|
||||
//rootProject.name = "positions"
|
||||
|
||||
// WinBoLL 项目编译设置
|
||||
//include ':winboll'
|
||||
//include ':libwinboll'
|
||||
//rootProject.name = "winboll"
|
||||
|
||||
// RegExpUtils 项目编译设置
|
||||
//include ':regexputils'
|
||||
//rootProject.name = "regexputils"
|
||||
|
||||
// GPSRelaySentinel 项目编译设置
|
||||
//include ':gpsrelaysentinel'
|
||||
//include ':libgpsrelaysentinel'
|
||||
//rootProject.name = "gpsrelaysentinel"
|
||||
|
||||
// Gallery 项目编译设置
|
||||
//include ':gallery'
|
||||
//rootProject.name = "gallery"
|
||||
|
||||
// DebugTemp 项目编译设置
|
||||
//include ':debugtemp'
|
||||
//include ':libdebugtemp'
|
||||
//rootProject.name = "debugtemp"
|
||||
|
||||
// AutoNFC 项目编译设置
|
||||
//include ':autonfc'
|
||||
//rootProject.name = "autonfc"
|
||||
|
||||
Reference in New Issue
Block a user