diff --git a/.gitignore b/.gitignore index 3be31ff..a0f25db 100644 --- a/.gitignore +++ b/.gitignore @@ -98,4 +98,46 @@ lint-results.html /winboll.properties /local.properties /settings.gradle -/gradle.properties \ No newline at end of file +/gradle.properties + +## WinBoLL 项目配置 +#.git +#.gitignore +#.gitmodules +#.gradle +#.winboll +#GenKeyStore +#LICENSE +#LICENSE-Private-Demo +#LICENSE-Private-Demo_docs +#README.md +#aes +#appbase +appkey.jks +appkey.keystore +autonfc +#build.gradle +contacts +debugtemp +gallery +gpsrelaysentinel +#gradle +gradle.properties +#gradle.properties-android-demo +#gradle.properties-androidx-demo +#gradlew +libaes +libappbase +libdebugtemp +libgpsrelaysentinel +#libwinboll +local.properties +#local.properties-demo +mymessagemanager +positions +powerbell +settings.gradle +#settings.gradle-demo +#winboll +winboll.properties +#winboll.properties-demo diff --git a/autonfc/.gitignore b/autonfc/.gitignore deleted file mode 100644 index 42afabf..0000000 --- a/autonfc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/autonfc/README.md b/autonfc/README.md deleted file mode 100644 index 7421e1d..0000000 --- a/autonfc/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# AutoNFC - -#### 介绍 -NFC 卡应用,主要管理 NFC 卡接触手机的动作响应,NFC 接触状态用于作为其他应用激活活动动作的启动令牌。 - -#### 软件架构 -适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。 -也适配安卓应用 [AndroidIDE] 的 Gradle 编译结构。 - - -#### Gradle 编译说明 -调试版编译命令 :gradle assembleBetaDebug -阶段版编译命令 :bash .winboll/bashPublishAPKAddTag.sh autonfc - -#### 使用说明 - -#### 参与贡献 - -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 : ZhanGSKen(ZhanGSKen) -4. 新建 Pull Request - - -#### 特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) - -#### 参考文档 diff --git a/autonfc/app_update_description.txt b/autonfc/app_update_description.txt deleted file mode 100644 index 8b13789..0000000 --- a/autonfc/app_update_description.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/autonfc/build.gradle b/autonfc/build.gradle deleted file mode 100644 index 92c012a..0000000 --- a/autonfc/build.gradle +++ /dev/null @@ -1,119 +0,0 @@ -apply plugin: 'com.android.application' -apply from: '../.winboll/winboll_app_build.gradle' -apply from: '../.winboll/winboll_lint_build.gradle' - -def genVersionName(def versionName){ - // 检查编译标志位配置 - assert (winbollBuildProps['stageCount'] != null) - assert (winbollBuildProps['baseVersion'] != null) - // 保存基础版本号 - winbollBuildProps.setProperty("baseVersion", "${versionName}"); - //保存编译标志配置 - FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) - winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); - fos.close(); - - // 返回编译版本号 - return "${versionName}." + winbollBuildProps['stageCount'] -} - -android { - // 适配MIUI12 - compileSdkVersion 30 - buildToolsVersion "30.0.3" - - defaultConfig { - applicationId "cc.winboll.studio.autonfc" - minSdkVersion 23 - // 适配MIUI12 - targetSdkVersion 30 - versionCode 1 - // versionName 更新后需要手动设置 - // .winboll/winbollBuildProps.properties 文件的 stageCount=0 - // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" - versionName "15.11" - if(true) { - versionName = genVersionName("${versionName}") - } - } - - // 米盟 SDK - packagingOptions { - doNotStrip "*/*/libmimo_1011.so" - } - - sourceSets { - main { - jniLibs.srcDirs = ['libs'] // 若SO库放在libs目录下 - } - } -} - -dependencies { - - api 'com.google.code.gson:gson:2.10.1' - - // 下拉控件 - api 'com.baoyz.pullrefreshlayout:library:1.2.0' - - // SSH - api 'com.jcraft:jsch:0.1.55' - // Html 解析 - api 'org.jsoup:jsoup:1.13.1' - // 二维码类库 - api 'com.google.zxing:core:3.4.1' - api 'com.journeyapps:zxing-android-embedded:3.6.0' - // 应用介绍页类库 - api 'io.github.medyo:android-about-page:2.0.0' - // 网络连接类库 - api 'com.squareup.okhttp3:okhttp:4.4.1' - // OkHttp网络请求 - implementation 'com.squareup.okhttp3:okhttp:3.14.9' - // FastJSON解析 - implementation 'com.alibaba:fastjson:1.2.76' - - // AndroidX 类库 - /*api 'androidx.appcompat:appcompat:1.1.0' - //api 'com.google.android.material:material:1.4.0' - //api 'androidx.viewpager:viewpager:1.0.0' - //api 'androidx.vectordrawable:vectordrawable:1.1.0' - //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0' - //api 'androidx.fragment:fragment:1.1.0'*/ - - - // 米盟 - api 'com.miui.zeus:mimo-ad-sdk:5.3.+'//请使用最新版sdk - //注意:以下5个库必须要引入 - //implementation 'androidx.appcompat:appcompat:1.4.1' - api 'androidx.recyclerview:recyclerview:1.0.0' - api 'com.google.code.gson:gson:2.8.5' - api 'com.github.bumptech.glide:glide:4.9.0' - //annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0' - - implementation "androidx.annotation:annotation:1.3.0" - implementation "androidx.core:core:1.6.0" - implementation "androidx.drawerlayout:drawerlayout:1.1.1" - implementation "androidx.preference:preference:1.1.1" - implementation "androidx.viewpager:viewpager:1.0.0" - implementation "com.google.android.material:material:1.4.0" - implementation "com.google.guava:guava:24.1-jre" - /* - implementation "io.noties.markwon:core:$markwonVersion" - implementation "io.noties.markwon:ext-strikethrough:$markwonVersion" - implementation "io.noties.markwon:linkify:$markwonVersion" - implementation "io.noties.markwon:recycler:$markwonVersion" - */ - implementation 'com.termux:terminal-emulator:0.118.0' - implementation 'com.termux:terminal-view:0.118.0' - implementation 'com.termux:termux-shared:0.118.0' - - // WinBoLL库 nexus.winboll.cc 地址 - api 'cc.winboll.studio:libaes:15.15.2' - api 'cc.winboll.studio:libappbase:15.15.11' - - // WinBoLL备用库 jitpack.io 地址 - //api 'com.github.ZhanGSKen:AES:aes-v15.15.7' - //api 'com.github.ZhanGSKen:APPBase:appbase-v15.15.4' - - api fileTree(dir: 'libs', include: ['*.jar']) -} diff --git a/autonfc/build.properties b/autonfc/build.properties deleted file mode 100644 index 4599e56..0000000 --- a/autonfc/build.properties +++ /dev/null @@ -1,8 +0,0 @@ -#Created by .winboll/winboll_app_build.gradle -#Mon Mar 16 18:30:19 GMT 2026 -stageCount=0 -libraryProject= -baseVersion=15.11 -publishVersion=15.0.0 -buildCount=54 -baseBetaVersion=15.0.1 diff --git a/autonfc/proguard-rules.pro b/autonfc/proguard-rules.pro deleted file mode 100644 index 64b4a05..0000000 --- a/autonfc/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# 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 \ No newline at end of file diff --git a/autonfc/src/beta/AndroidManifest.xml b/autonfc/src/beta/AndroidManifest.xml deleted file mode 100644 index ee78d9f..0000000 --- a/autonfc/src/beta/AndroidManifest.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - diff --git a/autonfc/src/beta/res/values/strings.xml b/autonfc/src/beta/res/values/strings.xml deleted file mode 100644 index 3c165aa..0000000 --- a/autonfc/src/beta/res/values/strings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - AutoNFC✌ - - diff --git a/autonfc/src/main/AndroidManifest.xml b/autonfc/src/main/AndroidManifest.xml deleted file mode 100644 index 97234a5..0000000 --- a/autonfc/src/main/AndroidManifest.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/App.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/App.java deleted file mode 100644 index d64ac77..0000000 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/App.java +++ /dev/null @@ -1,344 +0,0 @@ -package cc.winboll.studio.autonfc; - -import android.app.Activity; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.res.Resources; -import android.graphics.Typeface; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.text.TextUtils; -import android.util.Log; -import android.view.Gravity; -import android.view.Menu; -import android.view.MenuItem; -import android.view.ViewGroup; -import android.widget.HorizontalScrollView; -import android.widget.ScrollView; -import android.widget.TextView; -import android.widget.Toast; -import cc.winboll.studio.libappbase.GlobalApplication; -import cc.winboll.studio.libappbase.ToastUtils; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.Thread.UncaughtExceptionHandler; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.concurrent.atomic.AtomicBoolean; - -public class App extends GlobalApplication { - - private static Handler MAIN_HANDLER = new Handler(Looper.getMainLooper()); - - @Override - public void onCreate() { - super.onCreate(); - - // 初始化 Toast 框架 -// ToastUtils.init(this); -// // 设置 Toast 布局样式 -// //ToastUtils.setView(R.layout.view_toast); -// ToastUtils.setStyle(new WhiteToastStyle()); -// ToastUtils.setGravity(Gravity.BOTTOM, 0, 200); -// - //CrashHandler.getInstance().registerGlobal(this); - //CrashHandler.getInstance().registerPart(this); - } - - public static void write(InputStream input, OutputStream output) throws IOException { - byte[] buf = new byte[1024 * 8]; - int len; - while ((len = input.read(buf)) != -1) { - output.write(buf, 0, len); - } - } - - public static void write(File file, byte[] data) throws IOException { - File parent = file.getParentFile(); - if (parent != null && !parent.exists()) parent.mkdirs(); - - ByteArrayInputStream input = new ByteArrayInputStream(data); - FileOutputStream output = new FileOutputStream(file); - try { - write(input, output); - } finally { - closeIO(input, output); - } - } - - public static String toString(InputStream input) throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - write(input, output); - try { - return output.toString("UTF-8"); - } finally { - closeIO(input, output); - } - } - - public static void closeIO(Closeable... closeables) { - for (Closeable closeable : closeables) { - try { - if (closeable != null) closeable.close(); - } catch (IOException ignored) {} - } - } - - public static class CrashHandler { - - public static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler(); - - private static CrashHandler sInstance; - - private PartCrashHandler mPartCrashHandler; - - public static CrashHandler getInstance() { - if (sInstance == null) { - sInstance = new CrashHandler(); - } - return sInstance; - } - - public void registerGlobal(Context context) { - registerGlobal(context, null); - } - - public void registerGlobal(Context context, String crashDir) { - Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandlerImpl(context.getApplicationContext(), crashDir)); - } - - public void unregister() { - Thread.setDefaultUncaughtExceptionHandler(DEFAULT_UNCAUGHT_EXCEPTION_HANDLER); - } - - public void registerPart(Context context) { - unregisterPart(context); - mPartCrashHandler = new PartCrashHandler(context.getApplicationContext()); - MAIN_HANDLER.postAtFrontOfQueue(mPartCrashHandler); - } - - public void unregisterPart(Context context) { - if (mPartCrashHandler != null) { - mPartCrashHandler.isRunning.set(false); - mPartCrashHandler = null; - } - } - - private static class PartCrashHandler implements Runnable { - - private final Context mContext; - - public AtomicBoolean isRunning = new AtomicBoolean(true); - - public PartCrashHandler(Context context) { - this.mContext = context; - } - - @Override - public void run() { - while (isRunning.get()) { - try { - Looper.loop(); - } catch (final Throwable e) { - e.printStackTrace(); - if (isRunning.get()) { - MAIN_HANDLER.post(new Runnable(){ - - @Override - public void run() { - Toast.makeText(mContext, e.toString(), Toast.LENGTH_LONG).show(); - } - }); - } else { - if (e instanceof RuntimeException) { - throw (RuntimeException)e; - } else { - throw new RuntimeException(e); - } - } - } - } - } - } - - private static class UncaughtExceptionHandlerImpl implements UncaughtExceptionHandler { - - private static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss"); - - private final Context mContext; - - private final File mCrashDir; - - public UncaughtExceptionHandlerImpl(Context context, String crashDir) { - this.mContext = context; - this.mCrashDir = TextUtils.isEmpty(crashDir) ? new File(mContext.getExternalCacheDir(), "crash") : new File(crashDir); - } - - @Override - public void uncaughtException(Thread thread, Throwable throwable) { - try { - - String log = buildLog(throwable); - writeLog(log); - - try { - Intent intent = new Intent(mContext, CrashActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(Intent.EXTRA_TEXT, log); - mContext.startActivity(intent); - } catch (Throwable e) { - e.printStackTrace(); - writeLog(e.toString()); - } - - throwable.printStackTrace(); - android.os.Process.killProcess(android.os.Process.myPid()); - System.exit(0); - - } catch (Throwable e) { - if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(thread, throwable); - } - } - - private String buildLog(Throwable throwable) { - String time = DATE_FORMAT.format(new Date()); - - String versionName = "unknown"; - long versionCode = 0; - try { - PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0); - versionName = packageInfo.versionName; - versionCode = Build.VERSION.SDK_INT >= 28 ? packageInfo.getLongVersionCode() : packageInfo.versionCode; - } catch (Throwable ignored) {} - - LinkedHashMap head = new LinkedHashMap(); - head.put("Time Of Crash", time); - head.put("Device", String.format("%s, %s", Build.MANUFACTURER, Build.MODEL)); - head.put("Android Version", String.format("%s (%d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT)); - head.put("App Version", String.format("%s (%d)", versionName, versionCode)); - head.put("Kernel", getKernel()); - head.put("Support Abis", Build.VERSION.SDK_INT >= 21 && Build.SUPPORTED_ABIS != null ? Arrays.toString(Build.SUPPORTED_ABIS): "unknown"); - head.put("Fingerprint", Build.FINGERPRINT); - - StringBuilder builder = new StringBuilder(); - - for (String key : head.keySet()) { - if (builder.length() != 0) builder.append("\n"); - builder.append(key); - builder.append(" : "); - builder.append(head.get(key)); - } - - builder.append("\n\n"); - builder.append(Log.getStackTraceString(throwable)); - - return builder.toString(); - } - - private void writeLog(String log) { - String time = DATE_FORMAT.format(new Date()); - File file = new File(mCrashDir, "crash_" + time + ".txt"); - try { - write(file, log.getBytes("UTF-8")); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - private static String getKernel() { - try { - return App.toString(new FileInputStream("/proc/version")).trim(); - } catch (Throwable e) { - return e.getMessage(); - } - } - } - } - - public static final class CrashActivity extends Activity { - - private String mLog; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTheme(android.R.style.Theme_DeviceDefault); - setTitle("App Crash"); - - mLog = getIntent().getStringExtra(Intent.EXTRA_TEXT); - - ScrollView contentView = new ScrollView(this); - contentView.setFillViewport(true); - - HorizontalScrollView horizontalScrollView = new HorizontalScrollView(this); - - TextView textView = new TextView(this); - int padding = dp2px(16); - textView.setPadding(padding, padding, padding, padding); - textView.setText(mLog); - textView.setTextIsSelectable(true); - textView.setTypeface(Typeface.DEFAULT); - textView.setLinksClickable(true); - - horizontalScrollView.addView(textView); - contentView.addView(horizontalScrollView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - - setContentView(contentView); - } - - private void restart() { - Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName()); - if (intent != null) { - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } - finish(); - android.os.Process.killProcess(android.os.Process.myPid()); - System.exit(0); - } - - private static int dp2px(float dpValue) { - final float scale = Resources.getSystem().getDisplayMetrics().density; - return (int) (dpValue * scale + 0.5f); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, android.R.id.copy, 0, android.R.string.copy) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.copy: - ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); - cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog)); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onBackPressed() { - restart(); - } - } -} diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/MainActivity.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/MainActivity.java deleted file mode 100644 index 03743b7..0000000 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/MainActivity.java +++ /dev/null @@ -1,180 +0,0 @@ -package cc.winboll.studio.autonfc; - -import android.app.PendingIntent; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.nfc.NfcAdapter; -import android.os.Bundle; -import android.os.IBinder; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import cc.winboll.studio.autonfc.nfc.ActionDialog; -import cc.winboll.studio.autonfc.nfc.AutoNFCService; -import cc.winboll.studio.autonfc.nfc.NFCInterfaceActivity; -import cc.winboll.studio.libappbase.LogActivity; -import cc.winboll.studio.libappbase.LogUtils; - -public class MainActivity extends AppCompatActivity { - - public static final String TAG = "MainActivity"; - - private NfcAdapter mNfcAdapter; - private PendingIntent mPendingIntent; - private AutoNFCService mService; - private boolean mBound = false; - - // 服务连接 - private ServiceConnection mConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - AutoNFCService.LocalBinder binder = (AutoNFCService.LocalBinder) service; - mService = binder.getService(); - mBound = true; - LogUtils.d(TAG, "onServiceConnected: 服务已绑定"); - - // 关键:把 Activity 传给 Service,用于回调 - mService.attachActivity(MainActivity.this); - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mBound = false; - mService = null; - LogUtils.d(TAG, "onServiceDisconnected: 服务已断开"); - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - - // 初始化 NFC - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - Intent nfcIntent = new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - mPendingIntent = PendingIntent.getActivity(this, 0, nfcIntent, 0); - - LogUtils.d(TAG, "onCreate() -> NFC 监听已绑定到 MainActivity"); - } - - @Override - protected void onStart() { - super.onStart(); - // 绑定服务 - Intent intent = new Intent(this, AutoNFCService.class); - bindService(intent, mConnection, Context.BIND_AUTO_CREATE); - LogUtils.d(TAG, "onStart: 绑定服务"); - } - - @Override - protected void onStop() { - super.onStop(); - // 解绑服务 - if (mBound) { - unbindService(mConnection); - mBound = false; - LogUtils.d(TAG, "onStop: 解绑服务"); - } - } - - @Override - protected void onResume() { - super.onResume(); - LogUtils.d(TAG, "onResume() -> 开启 NFC 前台分发"); - if (mNfcAdapter != null) { - mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null); - } - } - - @Override - protected void onPause() { - super.onPause(); - LogUtils.d(TAG, "onPause() -> 关闭 NFC 前台分发"); - if (mNfcAdapter != null) { - mNfcAdapter.disableForegroundDispatch(this); - } - } - - // NFC 卡片靠近唯一入口 - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - LogUtils.d(TAG, "onNewIntent() -> 检测到 NFC 卡片"); - - // 把 NFC 事件交给 Service 处理 - if (mBound && mService != null) { - mService.handleNfcIntent(intent); - } else { - LogUtils.e(TAG, "服务未绑定,无法处理 NFC"); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.main_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - - if (id == R.id.menu_log) { - LogActivity.startLogActivity(this); - return true; - } - - return super.onOptionsItemSelected(item); - } - - public void onNFCInterfaceActivity(View view) { - startActivity(new Intent(this, NFCInterfaceActivity.class)); - } - - // ========================= 【新增】关键方法:由 Service 回调来弹出对话框 ========================= - /** - * Service 解析完 NFC 数据后,回调此方法在 Activity 中弹出对话框 - */ - public void showNfcActionDialog(final String nfcData) { - LogUtils.d(TAG, "showNfcActionDialog() -> Activity 存活,安全弹出对话框"); - - // Activity 正在运行,直接弹框,绝对不会报 BadTokenException - final ActionDialog dialog = new ActionDialog(this); - dialog.setNfcData(nfcData); - dialog.setButtonClickListener(new ActionDialog.OnButtonClickListener() { - @Override - public void onBuildClick() { - LogUtils.d(TAG, "点击 Build"); - if (mService != null) { - mService.executeTermuxCommand(AutoNFCService.ACTION_BUILD, nfcData); - } - dialog.dismiss(); - } - - @Override - public void onViewClick() { - LogUtils.d(TAG, "点击 View"); - if (mService != null) { - mService.executeTermuxCommand(AutoNFCService.ACTION_BUILD_VIEW, nfcData); - } - dialog.dismiss(); - } - - @Override - public void onCancelClick() { - dialog.dismiss(); - } - }); - - dialog.show(); - } -} - diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/models/NfcTermuxCmd.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/models/NfcTermuxCmd.java deleted file mode 100644 index faab4cb..0000000 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/models/NfcTermuxCmd.java +++ /dev/null @@ -1,66 +0,0 @@ -package cc.winboll.studio.autonfc.models; - -/** - * @Author 豆包&ZhanGSKen - * @Date 2026/03/16 09:38 - */ -public class NfcTermuxCmd { - - private String script; // 要执行的预制脚本名(如 auth.sh) - private String[] args; // 脚本参数 - private String workDir; // 工作目录 - private boolean background; // 是否后台执行 - private String resultDir; // 结果输出目录(可为 null) - - public NfcTermuxCmd() { - } - - public NfcTermuxCmd(String script, String[] args, String workDir, boolean background, String resultDir) { - this.script = script; - this.args = args; - this.workDir = workDir; - this.background = background; - this.resultDir = resultDir; - } - - public String getScript() { - return script; - } - - public void setScript(String script) { - this.script = script; - } - - public String[] getArgs() { - return args; - } - - public void setArgs(String[] args) { - this.args = args; - } - - public String getWorkDir() { - return workDir; - } - - public void setWorkDir(String workDir) { - this.workDir = workDir; - } - - public boolean isBackground() { - return background; - } - - public void setBackground(boolean background) { - this.background = background; - } - - public String getResultDir() { - return resultDir; - } - - public void setResultDir(String resultDir) { - this.resultDir = resultDir; - } -} - diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/ActionDialog.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/ActionDialog.java deleted file mode 100644 index c3f65d7..0000000 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/ActionDialog.java +++ /dev/null @@ -1,123 +0,0 @@ -package cc.winboll.studio.autonfc.nfc; - -import android.app.Dialog; -import android.content.Context; -import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; - -import cc.winboll.studio.autonfc.R; -import cc.winboll.studio.libappbase.LogUtils; - -/** - * 自定义对话框类,用于与用户交互,展示 NFC 相关操作选项 - * 兼容 Java 7 语法 - * - * @author 豆包&ZhanGSKen - * @create 2025-08-15 - * @lastModify 2026-03-17 - */ -public class ActionDialog extends Dialog { - - private static final String TAG = "ActionDialog"; - private String mNfcData; - private OnButtonClickListener mClickListener; - - /** - * 构造函数 - */ - public ActionDialog(Context context) { - super(context); - initDialog(); - } - - /** - * 设置 NFC 数据 - */ - public void setNfcData(String nfcData) { - this.mNfcData = nfcData; - LogUtils.d(TAG, "setNfcData() -> " + nfcData); - } - - /** - * 设置点击监听 - */ - public void setButtonClickListener(OnButtonClickListener listener) { - this.mClickListener = listener; - } - - /** - * 初始化布局 - */ - private void initDialog() { - setTitle("请选择操作"); - - LinearLayout layout = new LinearLayout(getContext()); - layout.setOrientation(LinearLayout.VERTICAL); - layout.setPadding(20, 20, 20, 20); - - addButtons(layout); - - setContentView(layout); - } - - /** - * 添加按钮 - */ - private void addButtons(LinearLayout layout) { - // Build 按钮 - Button btnBuild = createButton("Build", new View.OnClickListener() { - @Override - public void onClick(View v) { - LogUtils.d(TAG, "点击 Build"); - if (mClickListener != null) { - mClickListener.onBuildClick(); - } - } - }); - layout.addView(btnBuild); - - // View 按钮 - Button btnView = createButton("View", new View.OnClickListener() { - @Override - public void onClick(View v) { - LogUtils.d(TAG, "点击 View"); - if (mClickListener != null) { - mClickListener.onViewClick(); - } - } - }); - layout.addView(btnView); - - // 取消按钮 - Button btnCancel = createButton("Cancel", new View.OnClickListener() { - @Override - public void onClick(View v) { - LogUtils.d(TAG, "点击 Cancel"); - dismiss(); - } - }); - layout.addView(btnCancel); - } - - /** - * 创建按钮 - */ - private Button createButton(String text, View.OnClickListener listener) { - Button button = new Button(getContext()); - button.setText(text); - button.setPadding(10, 10, 10, 10); - button.setOnClickListener(listener); - return button; - } - - /** - * 回调接口 - */ - public interface OnButtonClickListener { - void onBuildClick(); - void onViewClick(); - void onCancelClick(); - } -} - diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCService.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCService.java deleted file mode 100644 index 0addf65..0000000 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCService.java +++ /dev/null @@ -1,202 +0,0 @@ -package cc.winboll.studio.autonfc.nfc; - -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.nfc.NdefMessage; -import android.nfc.NdefRecord; -import android.nfc.NfcAdapter; -import android.nfc.Tag; -import android.nfc.tech.Ndef; -import android.os.Binder; -import android.os.IBinder; - -import cc.winboll.studio.autonfc.MainActivity; -import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libappbase.ToastUtils; - -import java.nio.charset.Charset; -import java.util.Arrays; - -public class AutoNFCService extends Service { - - public static final String TAG = "AutoNFCService"; - - // ================= 已修改:更新为 Beta 包名 ================= - public static final String ACTION_BUILD = "cc.winboll.studio.winboll.termux.NfcTermuxBridgeActivity.ACTION_BUILD"; - public static final String ACTION_BUILD_VIEW = "cc.winboll.studio.winboll.termux.NfcTermuxBridgeActivity.ACTION_BUILD_VIEW"; - - private final IBinder mBinder = new LocalBinder(); - private String mNfcData; - private MainActivity mActivity; // 持有 Activity 引用,用于回调 - - // ========================= 生命周期 ========================= - @Override - public void onCreate() { - super.onCreate(); - LogUtils.d(TAG, "onCreate() -> 服务创建"); - // 移除:startForeground(NOTIFICATION_ID, buildNotification()); - } - - @Override - public void onDestroy() { - super.onDestroy(); - LogUtils.d(TAG, "onDestroy() -> 服务已停止"); - mActivity = null; // 释放引用 - } - - // ========================= 服务绑定 ========================= - @Override - public IBinder onBind(Intent intent) { - LogUtils.d(TAG, "onBind() -> 服务被绑定"); - return mBinder; - } - - @Override - public boolean onUnbind(Intent intent) { - LogUtils.d(TAG, "onUnbind() -> 服务解绑"); - // 移除:stopForeground(true); - stopSelf(); - return super.onUnbind(intent); - } - - // ========================= 对外暴露方法 ========================= - /** - * 绑定 Activity,用于回调显示对话框 - */ - public void attachActivity(MainActivity activity) { - this.mActivity = activity; - } - - /** - * 处理 NFC 意图 - */ - public void handleNfcIntent(Intent intent) { - LogUtils.d(TAG, "handleNfcIntent() -> 开始处理"); - - if (intent == null) { - LogUtils.e(TAG, "handleNfcIntent() -> 参数 intent 为空"); - return; - } - - String action = intent.getAction(); - LogUtils.d(TAG, "handleNfcIntent() -> Action = " + action); - - if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action) - || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) - || NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { - - LogUtils.d(TAG, "handleNfcIntent() -> 匹配 NFC 动作"); - - Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); - if (tag == null) { - LogUtils.e(TAG, "handleNfcIntent() -> Tag 为空"); - return; - } - - LogUtils.d(TAG, "handleNfcIntent() -> Tag ID = " + bytesToHexString(tag.getId())); - LogUtils.d(TAG, "handleNfcIntent() -> Tech List = " + Arrays.toString(tag.getTechList())); - - parseNdefData(tag); - } - } - - // ========================= 内部业务 ========================= - private void parseNdefData(Tag tag) { - LogUtils.d(TAG, "parseNdefData() -> 开始解析"); - - if (tag == null) return; - - Ndef ndef = Ndef.get(tag); - if (ndef == null) { - LogUtils.e(TAG, "parseNdefData() -> 不支持 NDEF 格式"); - return; - } - - try { - ndef.connect(); - NdefMessage msg = ndef.getNdefMessage(); - - if (msg == null || msg.getRecords() == null || msg.getRecords().length == 0) { - LogUtils.w(TAG, "parseNdefData() -> 卡片无数据"); - return; - } - - NdefRecord record = msg.getRecords()[0]; - byte[] payload = record.getPayload(); - - int langLen = payload[0] & 0x3F; - int start = 1 + langLen; - - if (start < payload.length) { - mNfcData = new String(payload, start, payload.length - start, Charset.forName("UTF-8")); - LogUtils.d(TAG, "parseNdefData() -> 读卡成功: " + mNfcData); - - // 关键:回调给 Activity 弹框,此时 Activity 一定是存活状态 - if (mActivity != null) { - mActivity.showNfcActionDialog(mNfcData); - } - } - - } catch (Exception e) { - LogUtils.e(TAG, "parseNdefData() -> 读取失败", e); - } finally { - try { - ndef.close(); - } catch (Exception e) { - // 忽略关闭异常 - } - } - } - - /** - * 执行 Termux 命令 - */ - public void executeTermuxCommand(String action, String nfcData) { - LogUtils.d(TAG, "executeTermuxCommand() -> 开始执行"); - - if (nfcData == null || nfcData.isEmpty()) { - ToastUtils.show("数据错误"); - return; - } - - try { - LogUtils.d(TAG, "executeTermuxCommand() -> 发送指令: " + nfcData); - - Intent bridgeIntent = new Intent(action); - - // ================= 已修改:使用 Beta 包名 ================= - bridgeIntent.setClassName( - "cc.winboll.studio.winboll.beta", - "cc.winboll.studio.winboll.termux.NfcTermuxBridgeActivity" - ); - - bridgeIntent.putExtra(Intent.EXTRA_TEXT, nfcData); - bridgeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - startActivity(bridgeIntent); - ToastUtils.show("指令已发送"); - } catch (Exception e) { - LogUtils.e(TAG, "executeTermuxCommand() -> 发送失败", e); - ToastUtils.show("发送失败"); - } - } - - // ========================= 工具方法 ========================= - private String bytesToHexString(byte[] bytes) { - if (bytes == null || bytes.length == 0) return ""; - StringBuilder sb = new StringBuilder(); - for (byte b : bytes) { - sb.append(String.format("%02X", b)); - } - return sb.toString(); - } - - // ========================= Binder ========================= - public class LocalBinder extends Binder { - public AutoNFCService getService() { - return AutoNFCService.this; - } - } -} - diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NFCInterfaceActivity.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NFCInterfaceActivity.java deleted file mode 100644 index 28b6f18..0000000 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NFCInterfaceActivity.java +++ /dev/null @@ -1,230 +0,0 @@ -package cc.winboll.studio.autonfc.nfc; - -import android.app.Activity; -import android.app.PendingIntent; -import android.content.Intent; -import android.nfc.NfcAdapter; -import android.nfc.Tag; -import android.os.Bundle; -import android.view.View; -import android.widget.EditText; -import android.widget.TextView; -import android.widget.Toast; -import cc.winboll.studio.autonfc.R; -import cc.winboll.studio.autonfc.models.NfcTermuxCmd; -import cc.winboll.studio.libappbase.LogUtils; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -public class NFCInterfaceActivity extends Activity { - - public static final String TAG = "NFCInterfaceActivity"; - - private EditText et_script; - private EditText et_args; - private EditText et_workDir; - private EditText et_background; - private EditText et_resultDir; - - private TextView tvResult; - private TextView tvStatus; - - private NfcAdapter mNfcAdapter; - private PendingIntent mNfcPendingIntent; - private Tag mCurrentTag; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_nfc_interface); - initView(); - initNfc(); - } - - private void initView() { - et_script = findViewById(R.id.et_script); - et_args = findViewById(R.id.et_args); - et_workDir = findViewById(R.id.et_workDir); - et_background = findViewById(R.id.et_background); - et_resultDir = findViewById(R.id.et_resultDir); - - tvResult = findViewById(R.id.tv_result); - tvStatus = findViewById(R.id.tv_status); - } - - private void initNfc() { - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - - if (mNfcAdapter == null) { - tvStatus.setText("设备不支持NFC"); - return; - } - if (!mNfcAdapter.isEnabled()) { - tvStatus.setText("请开启NFC"); - return; - } - - Intent nfcIntent = new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - mNfcPendingIntent = PendingIntent.getActivity(this, 0, nfcIntent, PendingIntent.FLAG_UPDATE_CURRENT); - - tvStatus.setText("NFC已启动,等待卡片靠近"); - } - - @Override - protected void onResume() { - super.onResume(); - if (mNfcAdapter != null && mNfcAdapter.isEnabled()) { - mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent, null, null); - } - } - - @Override - protected void onPause() { - super.onPause(); - if (mNfcAdapter != null) { - mNfcAdapter.disableForegroundDispatch(this); - } - mCurrentTag = null; - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - mCurrentTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); - if (mCurrentTag == null) return; - - tvStatus.setText("卡片已连接,解析中..."); - readNfc(); - } - - // ------------------------------------------------------------------------- - // 读取 NFC(完全委托给工具类) - // ------------------------------------------------------------------------- - private void readNfc() { - try { - NfcTermuxCmd cmd = NfcUtils.readTag(mCurrentTag); - if (cmd == null) { - tvStatus.setText("读取成功:标签为空"); - tvResult.setText(""); - // 清空窗体 - clearUiFields(); - return; - } - - // 核心改动:读取成功后,同时更新详情显示 和 窗体输入框 - updateUiWithCmd(cmd); - - } catch (Exception e) { - LogUtils.e(TAG, "readNfc 失败", e); - tvStatus.setText("读取失败:" + e.getMessage()); - // 出错时清空窗体 - clearUiFields(); - } - } - - // ------------------------------------------------------------------------- - // 新增:根据读取到的 Cmd 填充 UI(详情 + 窗体) - // ------------------------------------------------------------------------- - private void updateUiWithCmd(NfcTermuxCmd cmd) { - if (cmd == null) return; - - String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(new Date()); - String show = "【读取时间】 " + time + "\n\n" - + "【解析结果】\n" - + "script: " + cmd.getScript() + "\n" - + "args: " + (cmd.getArgs() != null ? String.join(", ", cmd.getArgs()) : "[]") + "\n" - + "workDir: " + cmd.getWorkDir() + "\n" - + "background: " + cmd.isBackground() + "\n" - + "resultDir: " + cmd.getResultDir(); - - tvResult.setText(show); - tvStatus.setText("读取成功!"); - - // 👇 关键逻辑:自动填入窗体(每次读取后都会覆盖输入框) - et_script.setText(cmd.getScript() != null ? cmd.getScript() : ""); - et_args.setText(cmd.getArgs() != null ? String.join(",", cmd.getArgs()) : ""); - et_workDir.setText(cmd.getWorkDir() != null ? cmd.getWorkDir() : ""); - et_background.setText(String.valueOf(cmd.isBackground())); - et_resultDir.setText(cmd.getResultDir() != null ? cmd.getResultDir() : ""); - } - - // ------------------------------------------------------------------------- - // 辅助:清空所有输入框 - // ------------------------------------------------------------------------- - private void clearUiFields() { - et_script.setText(""); - et_args.setText(""); - et_workDir.setText(""); - et_background.setText(""); - et_resultDir.setText(""); - } - - // ------------------------------------------------------------------------- - // 写入按钮(委托给工具类) - // ------------------------------------------------------------------------- - public void onWriteClick(View view) { - if (mCurrentTag == null) { - showToast("请先靠近卡片"); - return; - } - - try { - NfcTermuxCmd cmd = buildCmdFromUI(); - NfcUtils.writeTag(mCurrentTag, cmd); - - tvStatus.setText("写入成功!"); - showToast("写入成功"); - readNfc(); // 写入后重读,此时会自动填入窗体 - - } catch (Exception e) { - LogUtils.e(TAG, "写入失败", e); - tvStatus.setText("写入失败:" + e.getMessage()); - showToast("写入失败"); - } - } - - // ------------------------------------------------------------------------- - // 填充调试数据 - // ------------------------------------------------------------------------- - public void onFillTestDataClick(View view) { - String testJson = "{\"script\":\"BuildWinBoLLProject.sh\",\"args\":[\"DebugTemp\"],\"workDir\":null,\"background\":true,\"resultDir\":null}"; - try { - NfcTermuxCmd cmd = NfcUtils.jsonToCmd(testJson); - et_script.setText(cmd.getScript()); - et_args.setText(cmd.getArgs() != null ? String.join(",", cmd.getArgs()) : ""); - et_workDir.setText(cmd.getWorkDir() != null ? cmd.getWorkDir() : ""); - et_background.setText(String.valueOf(cmd.isBackground())); - et_resultDir.setText(cmd.getResultDir() != null ? cmd.getResultDir() : ""); - - showToast("调试数据已填入"); - } catch (Exception e) { - showToast("解析失败"); - } - } - - // ------------------------------------------------------------------------- - // 从 UI 构建 NfcTermuxCmd - // ------------------------------------------------------------------------- - private NfcTermuxCmd buildCmdFromUI() { - String script = et_script.getText().toString().trim(); - String argsStr = et_args.getText().toString().trim(); - String workDir = et_workDir.getText().toString().trim(); - String bgStr = et_background.getText().toString().trim(); - String resultDir = et_resultDir.getText().toString().trim(); - - NfcTermuxCmd cmd = new NfcTermuxCmd(); - cmd.setScript(script); - cmd.setArgs(argsStr.isEmpty() ? new String[0] : argsStr.split(",")); - cmd.setWorkDir(workDir.isEmpty() ? null : workDir); - cmd.setBackground("true".equalsIgnoreCase(bgStr)); - cmd.setResultDir(resultDir.isEmpty() ? null : resultDir); - - return cmd; - } - - private void showToast(String msg) { - Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); - } -} - diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NfcStateMonitor.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NfcStateMonitor.java deleted file mode 100644 index a58fead..0000000 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NfcStateMonitor.java +++ /dev/null @@ -1,78 +0,0 @@ -package cc.winboll.studio.autonfc.nfc; - -import java.util.HashMap; -import java.util.Map; - -public class NfcStateMonitor { - private static Map sListenerMap = new HashMap<>(); - private static boolean sIsRunning = false; - - public static void startMonitor() { - if (sIsRunning) return; - sListenerMap = new HashMap<>(); - sIsRunning = true; - } - - public static void stopMonitor() { - if (!sIsRunning) return; - sIsRunning = false; - if (sListenerMap != null) { - sListenerMap.clear(); - sListenerMap = null; - } - } - - // 你原来的方法名:registerListener - public static void registerListener(String key, OnNfcStateListener listener) { - if (!sIsRunning || listener == null) return; - sListenerMap.put(key, listener); - } - - public static void unregisterListener(String key) { - if (!sIsRunning || key == null) return; - sListenerMap.remove(key); - } - - public static void notifyNfcConnected() { - if (!sIsRunning) return; - for (OnNfcStateListener l : sListenerMap.values()) { - l.onNfcConnected(); - } - } - - public static void notifyNfcDisconnected() { - if (!sIsRunning) return; - for (OnNfcStateListener l : sListenerMap.values()) { - l.onNfcDisconnected(); - } - } - - public static void notifyReadSuccess(String data) { - if (!sIsRunning) return; - for (OnNfcStateListener l : sListenerMap.values()) { - l.onNfcReadSuccess(data); - } - } - - public static void notifyReadFail(String error) { - if (!sIsRunning) return; - for (OnNfcStateListener l : sListenerMap.values()) { - l.onNfcReadFail(error); - } - } - - public static void notifyWriteSuccess() { - if (!sIsRunning) return; - for (OnNfcStateListener l : sListenerMap.values()) { - l.onNfcWriteSuccess(); - } - } - - public static void notifyWriteFail(String error) { - if (!sIsRunning) return; - for (OnNfcStateListener l : sListenerMap.values()) { - l.onNfcWriteFail(error); - } - } -} - diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NfcUtils.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NfcUtils.java deleted file mode 100644 index 65ac597..0000000 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NfcUtils.java +++ /dev/null @@ -1,136 +0,0 @@ -package cc.winboll.studio.autonfc.nfc; - -/** - * @Author 豆包&ZhanGSKen - * @Date 2026/03/16 14:26 - */ -import android.nfc.NdefMessage; -import android.nfc.NdefRecord; -import android.nfc.Tag; -import android.nfc.tech.Ndef; -import com.google.gson.Gson; -import com.google.gson.JsonSyntaxException; -import cc.winboll.studio.autonfc.models.NfcTermuxCmd; -import cc.winboll.studio.libappbase.LogUtils; -import java.nio.charset.Charset; -import java.util.Locale; - -public class NfcUtils { - - public static final String TAG = "NfcUtils"; - private static Gson sGson = new Gson(); - - // ------------------------------------------------------------------------- - // 读取 NFC 标签并解析为 NfcTermuxCmd - // ------------------------------------------------------------------------- - public static NfcTermuxCmd readTag(Tag tag) throws Exception { - if (tag == null) { - LogUtils.e(TAG, "readTag: tag is null"); - return null; - } - - Ndef ndef = Ndef.get(tag); - if (ndef == null) { - LogUtils.e(TAG, "readTag: 不支持 NDEF"); - return null; - } - - try { - ndef.connect(); - NdefMessage msg = ndef.getNdefMessage(); - if (msg == null) return null; - - NdefRecord[] records = msg.getRecords(); - if (records == null || records.length == 0) return null; - - byte[] payload = records[0].getPayload(); - int status = payload[0] & 0xFF; - int langLen = status & 0x3F; - int start = 1 + langLen; - - if (start >= payload.length) return null; - - String json = new String(payload, start, payload.length - start, Charset.forName("UTF-8")); - LogUtils.d(TAG, "readTag: 提取 JSON -> " + json); - - return sGson.fromJson(json, NfcTermuxCmd.class); - } finally { - if (ndef != null && ndef.isConnected()) { - ndef.close(); - } - } - } - - // ------------------------------------------------------------------------- - // 写入 NfcTermuxCmd 到 NFC 标签 - // ------------------------------------------------------------------------- - public static void writeTag(Tag tag, NfcTermuxCmd cmd) throws Exception { - if (tag == null) throw new Exception("tag is null"); - - String json = sGson.toJson(cmd); - writeJson(tag, json); - } - - // ------------------------------------------------------------------------- - // 写入原始 JSON 字符串到 NFC - // ------------------------------------------------------------------------- - public static void writeJson(Tag tag, String json) throws Exception { - if (tag == null) throw new Exception("tag is null"); - - Ndef ndef = Ndef.get(tag); - if (ndef == null) throw new Exception("标签不支持 NDEF"); - - try { - ndef.connect(); - int maxSize = ndef.getMaxSize(); - int realSize = json.getBytes(Charset.forName("UTF-8")).length; - - if (realSize > maxSize) { - throw new Exception("数据过大 (" + realSize + ") > 容量 (" + maxSize + ")"); - } - - NdefRecord record = createTextRecord(json, true); - NdefMessage msg = new NdefMessage(new NdefRecord[]{record}); - - ndef.writeNdefMessage(msg); - LogUtils.d(TAG, "writeJson: 写入成功"); - } finally { - if (ndef != null && ndef.isConnected()) { - ndef.close(); - } - } - } - - // ------------------------------------------------------------------------- - // 创建 NFC 文本记录 - // ------------------------------------------------------------------------- - public static NdefRecord createTextRecord(String text, boolean isUtf8) { - byte[] langBytes = "en".getBytes(Charset.forName("US-ASCII")); - byte[] textBytes = text.getBytes(Charset.forName(isUtf8 ? "UTF-8" : "UTF-16")); - - int status = isUtf8 ? 0 : 0x80; - status |= langBytes.length & 0x3F; - - byte[] data = new byte[1 + langBytes.length + textBytes.length]; - data[0] = (byte) status; - System.arraycopy(langBytes, 0, data, 1, langBytes.length); - System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length); - - return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data); - } - - // ------------------------------------------------------------------------- - // 辅助:JSON -> NfcTermuxCmd - // ------------------------------------------------------------------------- - public static NfcTermuxCmd jsonToCmd(String json) throws JsonSyntaxException { - return sGson.fromJson(json, NfcTermuxCmd.class); - } - - // ------------------------------------------------------------------------- - // 辅助:NfcTermuxCmd -> JSON - // ------------------------------------------------------------------------- - public static String cmdToJson(NfcTermuxCmd cmd) { - return sGson.toJson(cmd); - } -} - diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/OnNfcStateListener.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/OnNfcStateListener.java deleted file mode 100644 index 4b149d5..0000000 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/OnNfcStateListener.java +++ /dev/null @@ -1,11 +0,0 @@ -package cc.winboll.studio.autonfc.nfc; - -public interface OnNfcStateListener { - void onNfcConnected(); // 无参数! - void onNfcDisconnected(); - void onNfcReadSuccess(String data); - void onNfcReadFail(String error); - void onNfcWriteSuccess(); - void onNfcWriteFail(String error); -} - diff --git a/autonfc/src/main/res/drawable-v24/ic_launcher_foreground.xml b/autonfc/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index c7bd21d..0000000 --- a/autonfc/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - diff --git a/autonfc/src/main/res/drawable/ic_launcher_background.xml b/autonfc/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index d5fccc5..0000000 --- a/autonfc/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/autonfc/src/main/res/layout/activity_main.xml b/autonfc/src/main/res/layout/activity_main.xml deleted file mode 100644 index a6032d0..0000000 --- a/autonfc/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - -