diff --git a/XixunPlayer/app/build.gradle b/XixunPlayer/app/build.gradle index 2035e49..5c9d3b9 100644 --- a/XixunPlayer/app/build.gradle +++ b/XixunPlayer/app/build.gradle @@ -11,7 +11,7 @@ android { minSdk 21 targetSdk 34 versionCode 1 - versionName "2.2.1-N" + versionName "2.2.19-config-lora" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -45,17 +45,17 @@ android { storePassword '123456' } - D { //A11 系统签名 卓策 + D { //A11 系统签名 卓策 --卓策系统签名+android.uid.system = 播放器常用普通签名 keyAlias 'xixun' keyPassword '123456' storeFile file('D:/zp/Android/GitConn/xixun-d.keystore') storePassword '123456' } - D_3566 { //A11 系统签名-新 + D_3576 { //A11 系统签名-新 雍慧 3576 3566 keyAlias 'platform' keyPassword 'youngfeel' - storeFile file('D:/XixunSoftware/ZP/conn/yf356x_android11_system.jks') + storeFile file('D:/zp/Android/GitConn/yf356x_android11_system.jks') storePassword 'youngfeel' } @@ -96,10 +96,10 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - signingConfig signingConfigs.D_3568 + signingConfig signingConfigs.D } debug { - signingConfig signingConfigs.D_3568 + signingConfig signingConfigs.D } } @@ -143,8 +143,3 @@ android.applicationVariants.configureEach { variant -> outputFileName = fileName } } - -//修改内容: -//D:\zp\Android\XixunPlayer_zp\XixunPlayer\app\build.gradle -//D:\zp\Android\XixunPlayer_zp\XixunPlayer\gradle\wrapper\gradle-wrapper.properties -//配置使用java17 \ No newline at end of file diff --git a/XixunPlayer/app/build_zp.gradle b/XixunPlayer/app/build_zp.gradle index 2035e49..7e63c76 100644 --- a/XixunPlayer/app/build_zp.gradle +++ b/XixunPlayer/app/build_zp.gradle @@ -11,99 +11,10 @@ android { minSdk 21 targetSdk 34 versionCode 1 - versionName "2.2.1-N" + versionName "2.2.19-Y-lora" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } -// buildTypes { -// release { -// minifyEnabled false -// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' -// } -// } - signingConfigs { - config { //常用 通用 - keyAlias 'xy' - keyPassword '111111' - storeFile file('D:/zp/Android/GitConn/xy_keystore') - //storeFile file('/home/yzd/work/sign/xy_keystore') - storePassword '111111' - } - - - M {//美格 //A7 - keyAlias 'xixun' - keyPassword '123456' - storeFile file('D:/XixunSoftware/ZP/conn/xixun-m.keystore') - storePassword '123456' - } - - Y5a { //A9 - keyAlias 'xixun' - keyPassword '123456' - storeFile file('D:/zp/Android/GitConn/xixun-c.keystore') - storePassword '123456' - } - - D { //A11 系统签名 卓策 - keyAlias 'xixun' - keyPassword '123456' - storeFile file('D:/zp/Android/GitConn/xixun-d.keystore') - storePassword '123456' - } - - D_3566 { //A11 系统签名-新 - keyAlias 'platform' - keyPassword 'youngfeel' - storeFile file('D:/XixunSoftware/ZP/conn/yf356x_android11_system.jks') - storePassword 'youngfeel' - } - - Y33 { // 系统签名 - keyAlias 'xixun' - keyPassword '123456' - storeFile file('D:/XixunSoftware/ZP/conn/xixun-x.keystore') - storePassword '123456' - } - - D_3568 {//3568 //恩泰世3568 - keyAlias 'systemkey' - keyPassword '123456' - storeFile file('D:/zp/Android/GitConn/platform.jks') - storePassword '123456' - } - D_gt {//3568 //高通 - keyAlias 'androiddebugkey' - keyPassword 'android' - storeFile file('D:/zp/Android/GitConn/platform.keystore') - storePassword 'android' - } - - a133 {//全志 a133 - keyAlias 'platform' - keyPassword 'youngfeel' - storeFile file('D:/zp/Android/GitConn/android11_system.jks') - storePassword 'youngfeel' - } - } - - - - - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - - signingConfig signingConfigs.D_3568 - } - debug { - signingConfig signingConfigs.D_3568 - - } - } - buildFeatures { aidl true } @@ -112,6 +23,52 @@ android { sourceCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11 } + signingConfigs { + X {//4418 + keyAlias 'xixun' + keyPassword '123456' + storeFile file('D:/develop/xixun/signedFile/keystore/xixun-x.keystore') + storePassword '123456' + } + Y {//210 + keyAlias 'xixun' + keyPassword '123456' + storeFile file('D:/develop/xixun/signedFile/keystore/xixun-y.keystore') + storePassword '123456' + } + D_3568a {//3568a 视美泰 + keyAlias 'keystore' + keyPassword 'android' + storeFile file('D:/develop/xixun/signedFile/keystore/keystore.jks') + storePassword 'android' + } + D_3568N {//3568 恩泰世 + keyAlias 'systemkey' + keyPassword '123456' + storeFile file('D:/_docs/comp/android/keystore/3568D恩泰世 123456.jks') + storePassword '123456' + } + D_YF {//3566 YF + keyAlias 'platform' + keyPassword 'youngfeel' + storeFile file('D:/_docs/comp/android/keystore/yf356x_android11_system.jks') + storePassword 'youngfeel' + } + } + buildTypes { + release { + lintOptions { + checkReleaseBuilds false + abortOnError false + } + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.D_3568N + } + debug { + signingConfig signingConfigs.D_3568N + } + } } dependencies { @@ -143,8 +100,3 @@ android.applicationVariants.configureEach { variant -> outputFileName = fileName } } - -//修改内容: -//D:\zp\Android\XixunPlayer_zp\XixunPlayer\app\build.gradle -//D:\zp\Android\XixunPlayer_zp\XixunPlayer\gradle\wrapper\gradle-wrapper.properties -//配置使用java17 \ No newline at end of file diff --git a/XixunPlayer/app/src/main/AndroidManifest.xml b/XixunPlayer/app/src/main/AndroidManifest.xml index 1649c52..01c11da 100644 --- a/XixunPlayer/app/src/main/AndroidManifest.xml +++ b/XixunPlayer/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + - - - 📌 - 注意事项 + + + + 📌 + 注意事项 + + + 设备需切换至联网模式并关联云平台账号,云服务器地址:https://www.ledokcloud.com + - - 设备需切换至联网模式并关联云平台账号,云服务器地址:https://www.ledokcloud.com + + + + 视频详解 @@ -166,7 +173,7 @@ - + 扫码下载APP @@ -244,14 +251,15 @@ appStep2: "2.创建并编辑节目", appStep3: "3.发送节目到设备", appNote: "设备需切换至热点模式,手机需连接该设备热点", - scanDownload: "扫码下载APP", + scanDownload: "下载APP", usbStep1: "1.节目文件存入U盘", usbStep2: "2.U盘接入设备", usbStep3: "3.系统自动播放", usbNote: "无设备模式限制,U盘即插即播", loading: "正在接收Android宽高...", loadFail: "接收宽高失败", - unknownNetwork: "未知网络" + unknownNetwork: "未知网络", + videoCommentary: "视频详解" }, // 英文 en: { @@ -272,14 +280,15 @@ appStep2: "2.Create and edit programs", appStep3: "3.Send programs to device", appNote: "The device must be switched to hotspot mode, and the mobile phone must connect to the device's hotspot", - scanDownload: "Scan to download APP", + scanDownload: "Download APP", usbStep1: "1.Save program files to USB", usbStep2: "2.Connect USB to device", usbStep3: "3.System plays automatically", usbNote: "No device mode restrictions, plug and play with USB", loading: "Receiving Android width and height...", loadFail: "Failed to receive width and height", - unknownNetwork: "Unknown Network" + unknownNetwork: "Unknown Network", + videoCommentary: "Video commentary" } }; @@ -375,7 +384,8 @@ const cardId = document.getElementById("cardId"); const cardVideos = document.querySelectorAll(".card-bg-video"); // 所有卡片视频 const infoBarVideo = document.querySelector(".info-bar-bg-video"); // 顶部信息栏视频 - + const qrcodeImg = document.getElementById("videoCommentaryQrcode"); + qrcodeImg.src = currentLang === "zh" ? "images/code_cn.png" : "images/code_en.png"; try { // ---------------------- 1. 获取并更新宽高 ---------------------- const sizeJson = AndroidBridge.getSizeFromAndroid(); diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/AIDLService.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/AIDLService.java index a2e3a89..48fd6dd 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/AIDLService.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/AIDLService.java @@ -110,7 +110,7 @@ public class AIDLService extends Service { @SuppressLint("ResourceType") @Override public String executeJosnCommand(String jsonstr) throws RemoteException { - Util.println("AIDL executeJsonCommand ..."+jsonstr);//{"_type":"DeleteTask","id":"652522a0e81d1e000009201a","sendTo":"yzd-player"} + Util.println("AIDL executeJson "+jsonstr);//{"_type":"DeleteTask","id":"652522a0e81d1e000009201a","sendTo":"yzd-player"} String commandId = null; try { var jsonBytes = jsonstr.getBytes(StandardCharsets.UTF_8); diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/AidlUtil.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/AidlUtil.java new file mode 100644 index 0000000..7697387 --- /dev/null +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/AidlUtil.java @@ -0,0 +1,175 @@ +package com.xixun.xixunplayer; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.IBinder; +import android.util.Log; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class AidlUtil { + // static final String ACTION_CONN ="xixun.intent.action.CONNECTION_INFO"; + static final String ACTION_PLAYER ="com.xixun.action.PlayerInfo"; + static final String ACTION_CARD_SYSTEM ="com.xixun.joey.aidlset.SettingsService"; + static final String ACTION_LIVE ="xixun.intent.action.Live"; + static final String ACTION_UPDATE ="xixun.intent.action.UPDATE_APK"; + static final String ACTION_JIESHUN ="com.xixun.xy.conn.JieShun"; + static final String ACTION_TaxiAppServer ="com.xixun.xy.conn.aidl.TaxiAppServer"; + static final String ACTION_CustomServer ="com.xixun.xy.conn.aidl.CustomService"; + static final String ACTION_ConnServer ="com.xixun.xy.conn.aidl.ConnService"; + static final String ACTION_AiServer ="com.sysolution.ai.AiAvatarService"; + public static final String PACKAGE_PLAYER="com.xixun.xixunplayer"; + public static final String PACKAGE_CARD_SYSTEM="com.xixun.joey.cardsystem"; + public static final String PACKAGE_LIVE="com.xixun.xy.live"; + public static final String PACKAGE_UPDATE="com.xixun.xy.update"; + public static final String PACKAGE_TAXIAPP = "net.sysolution.taxiapp"; + public static final String PACKAGE_CUSTOMAPP = "com.xixun.xixunledplayer"; + public static final String PACKAGE_BASICAPP = "net.sysolution.basicapp"; + public static final String PACKAGE_STARTER = "net.sysolution.starter"; + public static final String PACKAGE_DISPLAY = "com.xixun.display"; + public static final String PACKAGE_ORDER_VIDEO = "add.xixun.com.ordervideo"; + public static final String PACKAGE_JIESHUN = "com.xixun.stopguide"; + public static final String PACKAGE_TAXIAPP88 = "cn.trans88.taxiappkotlin"; + public static final String PACKAGE_AI = "com.sysolution.ai"; + public static final String PACKAGE_CONN = "com.xixun.xy.conn"; + + public static Intent newConnIntent(){ + Intent intent = new Intent(ACTION_ConnServer); + intent.setPackage(PACKAGE_CONN); + return intent; + } + public static Intent newAiIntent(){ + Intent intent = new Intent(ACTION_AiServer); + intent.setPackage(PACKAGE_AI); + return intent; + } + + public static Intent newCustomIntent(){ + Intent intent = new Intent(ACTION_CustomServer); + intent.setPackage(PACKAGE_CUSTOMAPP); + return intent; + } + + + public static Intent newTaxiAppIntent(){ + Intent intent = new Intent(ACTION_TaxiAppServer); + intent.setPackage(PACKAGE_TAXIAPP); + return intent; + } + + public static Intent newPlayerIntent(){ + Intent intent = new Intent(ACTION_PLAYER); + intent.setPackage(PACKAGE_PLAYER); + return intent; + } + public static Intent newCardSystemIntent(){ + Intent intent = new Intent(ACTION_CARD_SYSTEM); + intent.setPackage(PACKAGE_CARD_SYSTEM); + return intent; + } + public static Intent newLiveIntent(){ + Intent intent = new Intent(ACTION_LIVE); + intent.setPackage(PACKAGE_LIVE); + return intent; + } + public static Intent newUpdateIntent(){ + Intent intent = new Intent(ACTION_UPDATE); + intent.setPackage(PACKAGE_UPDATE); + return intent; + } + public static Intent newJieShunIntent(){ + Intent intent = new Intent(ACTION_JIESHUN); + intent.setPackage(PACKAGE_JIESHUN); + return intent; + } + + CountDownLatch latch = new CountDownLatch(1); + IBinder binder = null; + private Intent intent; + private Context ctx; + private int timeout; + private IBinder[] container = new IBinder[1]; + private ServiceConnection conn = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + binder =service; + ctx.unbindService(this); + latch.countDown(); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + Log.i("yzd", "aidl disconnected"); + } + }; + + public AidlUtil(Context context, Intent intent, int timeout) { + ctx = context; + this.intent =intent; + this.timeout = timeout; + } + + public AidlUtil(Context context, Intent intent) { + this(context, intent, 3000); + } + static int rate =200; + + public IBinder getIBinder() { + ctx.bindService(intent, conn, + Context.BIND_AUTO_CREATE); + try { + latch.await(timeout, TimeUnit.MILLISECONDS); + }catch(Exception e){ + e.printStackTrace(); + } + + if(binder==null) { + System.out.println("AIDL通讯建立失败"); + } + return binder; + } + + /*** + * Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent, + * "java.lang.IllegalArgumentException: Service Intent must be explicit" + * + * If you are using an implicit intent, and know only 1 target would answer this intent, + * This method will help you turn the implicit intent into the explicit form. + * + * Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466 + * @param context + * @param implicitIntent - The original implicit intent + * @return Explicit Intent created from the implicit original intent + */ + public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) { + // Retrieve all services that can match the given intent + PackageManager pm = context.getPackageManager(); + List resolveInfo = pm.queryIntentServices(implicitIntent, 0); + + // Make sure only one match was found + if (resolveInfo == null || resolveInfo.size() != 1) { + return null; + } + + // Get component info and create ComponentName + ResolveInfo serviceInfo = resolveInfo.get(0); + String packageName = serviceInfo.serviceInfo.packageName; + String className = serviceInfo.serviceInfo.name; + ComponentName component = new ComponentName(packageName, className); + + // Create a new intent. Use the old one for extras and such reuse + Intent explicitIntent = new Intent(implicitIntent); + + // Set the component to be explicit + explicitIntent.setComponent(component); + + return explicitIntent; + } + +} diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java index c64fb45..1a2444c 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java @@ -30,6 +30,8 @@ import androidx.core.content.ContextCompat; import com.xixun.joey.aidlset.CardService; import com.xixun.xy.conn.aidl.ConnService; +import org.json.JSONObject; + import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -182,7 +184,6 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac protected void onResume() { super.onResume(); Util.println(" ==>> MainActivity onResume >> "+hashCode()); - if(progView==null && insView==null) runOnUiThread(this::initProg); } @Override @@ -190,10 +191,9 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac super.onPause(); Util.println(" ==<< MainActivity onPause << "+hashCode()); state = 8; - stopProg(); } - CardService serviCard; + static CardService serviCard; ConnService serviXy; Intent intenCard; ServiceConnection connCard; @@ -246,31 +246,22 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac return "{\"width\":\"" + Util.screenWidth + "px\",\"height\":\"" + Util.screenHeight + "px\"}"; } @JavascriptInterface - public String getNetwork() { - // 获取当前网络类型 + public String getNetwork() {// 获取当前网络类型 NetworkTypeUtil.NetworkType networkType = NetworkTypeUtil.getCurrentNetworkType(MainActivity.this); String value = ""; switch (networkType) { case WIFI: - value = NetworkTypeUtil.getWifiSsid(MainActivity.this); - // 处理未获取到SSID的情况 - if (O.isEmpty(value)) value = "未知WiFi名称"; - System.out.println("当前是 WiFi 网络:" + value); + value = NetworkTypeUtil.getWifiSsid(MainActivity.this);// 处理未获取到SSID的情况 + if(O.isEmpty(value)) value = "未知WiFi名称"; break; case ETHERNET: - System.out.println("当前是有线网络"); break; - case CELLULAR: - // 细分蜂窝网络类型(2G/3G/4G) - String cellularSubType = NetworkTypeUtil.getCellularSubType(MainActivity.this); - value = cellularSubType; - System.out.println("当前是蜂窝网络:" + cellularSubType); + case CELLULAR:// 细分蜂窝网络类型(2G/3G/4G) + value = NetworkTypeUtil.getCellularSubType(MainActivity.this);; break; case NONE: - System.out.println("无网络连接"); break; case UNKNOWN: - System.out.println("未知网络类型(如蓝牙、VPN)"); break; } var IP = NetworkTypeUtil.getActiveNetworkIp(MainActivity.this); @@ -327,6 +318,7 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac Util.isScreenOn = serviCard.isScreenOpen(); Util.screenWidth = serviCard.getScreenWidth(); Util.screenHeight = serviCard.getScreenHeight(); + Util.println(" IsScreenOn: "+Util.isScreenOn+" screen: "+Util.screenWidth+" x "+Util.screenHeight); backView.invalidate(); if(Util.isScreenOn) initProg(); @@ -346,6 +338,7 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac bindService(intenCard, connCard, Context.BIND_AUTO_CREATE); services.add(connCard); + var connXy = new ServiceConnection() { public void onServiceDisconnected(ComponentName name) { serviXy = null; @@ -570,11 +563,17 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac AudioManager audioManager; AudioFocusRequest audioFocusRequest; public void stopProg() { + Util.println("---- Stop Prog\n"); avas.clear(); showHides.clear(); showeds.clear(); curAva = 0; curTimes = 1; + if(backViewL==null) setContentView(backView); + else { + setContentView(backViewL); + backViewL.loadUrl("file:///android_asset/local_page.html"); + } if(insView!=null) { insView.release(); insView = null; @@ -583,11 +582,6 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac progView.release(); progView = null; } - if(backViewL==null) setContentView(backView); - else { - setContentView(backViewL); - backViewL.loadUrl("file:///android_asset/local_page.html"); - } System.gc(); } public boolean delProgFile() { @@ -609,9 +603,11 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac return ok; } public void initProg() { + Util.println("\n---- Init Prog"); + if(progView!=null || insView!=null) return; state = 1; try { - Util.println("\nParse Insert Prog Json"); + Util.println(" Parse Insert Json"); var root = JSMap.fromClose(new BufferedInputStream(new FileInputStream(Util.programDir + "/insert"))); var task = root.jsmap("task"); if(task==null && root.containsKey("layers")) task = new JSMap("items", new JSList<>(new JSMap("_program", root))); @@ -626,7 +622,7 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac } var demand = 0; try { - Util.println("\nParse Prog Json"); + Util.println(" Parse Json"); var root = JSMap.fromClose(new BufferedInputStream(new FileInputStream(Util.programDir + "/program"))); var task = root.jsmap("task"); demand = root.intg("Demand"); @@ -646,10 +642,12 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac } if(insView!=null || progView!=null) { state = 5; - Util.println("Init Sync"); var ms = System.currentTimeMillis(); - if(demand==0 || progView==null) syncProg(ms, 0); - else { + if(demand==0 || progView==null) { + Util.println(" Init Sync"); + syncProg(ms, 0); + } else { + Util.println(" demand "+demand); avas.clear(); var page = progView.pages.get(demand-1); avas.add(page); @@ -669,8 +667,8 @@ public class MainActivity extends Activity implements Choreographer.FrameCallbac } else if(state != 7) state = 3; } public void initProg(byte[] json) { + Util.println("\n---- Init Prog with json"); try { - Util.println("\nParse Prog Json"); var root = JSMap.from(json); var task = root.jsmap("task"); if(task==null) { diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainService.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainService.java index c19645a..c9e4cd4 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainService.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainService.java @@ -7,14 +7,27 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.IBinder; +import com.xixun.xy.conn.aidl.ConnService; + import net.lingala.zip4j.ZipFile; +import org.json.JSONObject; + import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.Comparator; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; import gnph.util.IOs; +import gnph.util.JSList; +import gnph.util.JSMap; public class MainService extends Service { @@ -50,55 +63,161 @@ public class MainService extends Service { Util.makeText(MainService.this, "MEDIA_MOUNTED path: "+path+"\nImporting 正在导入 ...").show(); new Thread(()->{ try { - var zip = new ZipFile(path+"/program.zip"); - if(zip.isEncrypted()) zip.setPassword(pass); - long size = 0; - ByteArrayOutputStream jsonOut = null; - var headers = zip.getFileHeaders(); - for(var header : headers) { - size += header.getUncompressedSize(); - if("program".equals(header.getFileName())) IOs.writeClose(jsonOut = new ByteArrayOutputStream(), zip.getInputStream(header)); - } - if(jsonOut==null) { - Util.println("No program File"); - if(acti!=null) acti.runOnUiThread(() -> Util.makeText(acti, "No program File").show()); - return; - } - if(size==0) { - Util.println("zip size is 0"); - if(acti!=null) acti.runOnUiThread(() -> Util.makeText(acti, "zip size is 0").show()); - return; - } - Util.deleteFiles(size, null); - for(var header : headers) if(! "program".equals(header.getFileName())) { - Util.println(" name: " + header.getFileName()); - var fOut = new FileOutputStream(Util.programDir + "/" + header.getFileName()); - IOs.writeCloseIn(fOut, zip.getInputStream(header)); - fOut.flush(); - fOut.getFD().sync(); - fOut.close(); - } - var json = jsonOut.toByteArray(); - Util.println("Import Succeed"); - if(acti!=null) acti.runOnUiThread(() -> { - Util.makeText(acti, "Import Succeed 导入成功").show(); - acti.initProg(json); - }); - else { + if(Util.custom == Util.Custom.LoRa) { + System.out.println("周鹏测试"); + JSONObject jo = new JSONObject(); + jo.put("_id","123456"); + jo.put("_type","GetCardAlias"); + String alias = MainActivity.serviCard.executeJsonCommand(jo.toString()); + JSONObject js = new JSONObject(alias); + // 1. 从 JSONObject 中获取待解码的原始字符串(替换为你的 js.getString("alias")) + String rawBase64Str = js.getString("alias"); + // 2. 关键:Base64 字符串预处理(解决大部分格式非法问题) + String processedBase64Str = preprocessBase64(rawBase64Str); + // 3. 后续正常解码(使用预处理后的字符串) + byte[] decodeBytes = Base64.getDecoder().decode(processedBase64Str); + String originalStr = new String(decodeBytes, StandardCharsets.UTF_8); + System.out.println("周鹏获取别名"+originalStr); + + Util.downId = 0; + var ok = new AtomicBoolean(false); + if(MainActivity.ins!=null) { + var latch = new CountDownLatch(1); + MainActivity.ins.runOnUiThread(() -> { + ok.set(MainActivity.ins.delProgFile()); + latch.countDown(); + }); + try { + latch.await(); + } catch (InterruptedException ignored) {} + } + +// var id = Util.getCardId(); + var id = originalStr; + var dir = new File(path+"/"+id); + if(! dir.isDirectory()) { + Util.println("MEDIA_MOUNTED can't find "+id); + if(acti!=null) acti.runOnUiThread(() -> Util.makeText(acti, "MEDIA_MOUNTED can't find "+id).show()); + return; + } + long size = 0; + var files = dir.listFiles(); + Arrays.sort(files, (f1, f2) -> f1.getName().compareTo(f2.getName())); + for(var file : files) if(! file.getName().endsWith("json")) { + size += file.length(); + } + if(size==0) { + Util.println("files' size is 0"); + if(acti!=null) acti.runOnUiThread(() -> Util.makeText(acti, "files' size is 0").show()); + return; + } + var items = new JSList(); + var root = new JSMap( + "_type", "PlayXixunTask", + "Demand", 1, + "task", new JSMap( + "name", id, + "width", Util.screenWidth, + "height", Util.screenHeight, + "items", items + ) + ); + Util.deleteFiles(size, null); + for(var file : files) if(! file.getName().endsWith("json")) { + var name = file.getName(); + Util.println(" name: " + name); + var fOut = new FileOutputStream(Util.programDir + "/" + name); + IOs.writeCloseIn(fOut, new FileInputStream(file)); + fOut.flush(); + fOut.getFD().sync(); + fOut.close(); + items.add(new JSMap( + "_program", new JSMap( + "name", name, + "layers", new JSList<>(new JSMap( + "sources", new JSList<>(new JSMap( + "_type", "Video", + "id", name, + "md5", name, + "name", name, + "timeSpan", 43200, + "left", 0, + "top", 0, + "width", Util.screenWidth, + "height", Util.screenHeight, + "playTime", 0 + )) + )) + ) + )); + } var fOut = new FileOutputStream(Util.programDir + "/program"); - fOut.write(json); + root.write(fOut); var spaces = " ".getBytes(); for(int i=0;i<1000; i++) fOut.write(spaces); fOut.flush(); fOut.getFD().sync(); fOut.close(); - var inten = new Intent(MainService.this, MainActivity.class); - inten.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(inten); + Util.println("Import Succeed"); + if(acti!=null) acti.runOnUiThread(() -> { + Util.makeText(acti, "Import Succeed 导入成功").show(); + acti.initProg(); + }); + } else { + var zip = new ZipFile(path + "/program.zip"); + if(zip.isEncrypted()) zip.setPassword(pass); + long size = 0; + ByteArrayOutputStream jsonOut = null; + var headers = zip.getFileHeaders(); + for(var header : headers) { + size += header.getUncompressedSize(); + if ("program".equals(header.getFileName())) + IOs.writeClose(jsonOut = new ByteArrayOutputStream(), zip.getInputStream(header)); + } + if(jsonOut == null) { + Util.println("No program File"); + if (acti != null) + acti.runOnUiThread(() -> Util.makeText(acti, "No program File").show()); + return; + } + if(size == 0) { + Util.println("zip size is 0"); + if (acti != null) + acti.runOnUiThread(() -> Util.makeText(acti, "zip size is 0").show()); + return; + } + Util.deleteFiles(size, null); + for(var header : headers) + if (!"program".equals(header.getFileName())) { + Util.println(" name: " + header.getFileName()); + var fOut = new FileOutputStream(Util.programDir + "/" + header.getFileName()); + IOs.writeCloseIn(fOut, zip.getInputStream(header)); + fOut.flush(); + fOut.getFD().sync(); + fOut.close(); + } + var json = jsonOut.toByteArray(); + Util.println("Import Succeed"); + if(acti != null) acti.runOnUiThread(() -> { + Util.makeText(acti, "Import Succeed 导入成功").show(); + acti.initProg(json); + }); + else { + var fOut = new FileOutputStream(Util.programDir + "/program"); + fOut.write(json); + var spaces = " ".getBytes(); + for (int i = 0; i < 1000; i++) fOut.write(spaces); + fOut.flush(); + fOut.getFD().sync(); + fOut.close(); + var inten = new Intent(MainService.this, MainActivity.class); + inten.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(inten); + } + var inten = new Intent("com.xixun.AccessibilityService"); + inten.putExtra("newProgram", "USB"); + sendBroadcast(inten); } - var inten = new Intent("com.xixun.AccessibilityService"); - inten.putExtra("newProgram", "USB"); - sendBroadcast(inten); } catch (Exception e) { Util.printStackTrace(e); if(acti!=null) acti.runOnUiThread(() -> Util.makeText(acti, Util.toStr(e)).show()); @@ -127,4 +246,34 @@ public class MainService extends Service { public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); } + /** + * Base64 字符串预处理,清洗非法内容、补全合法格式 + * @param rawStr 原始待解码的 Base64 字符串 + * @return 符合标准 Base64 格式的预处理字符串 + */ + private static String preprocessBase64(String rawStr) { + if (rawStr == null || rawStr.trim().isEmpty()) { + throw new IllegalArgumentException("待解码的 Base64 字符串不能为空"); + } + + // 步骤1:剔除所有不可见字符(空格、换行、制表符等) + String cleanStr = rawStr.replaceAll("\\s+", ""); + + // 步骤2:剔除 Base64 标准字符之外的非法字符(仅保留 A-Z、a-z、0-9、+、/、=) + cleanStr = cleanStr.replaceAll("[^A-Za-z0-9+/=]", ""); + + // 步骤3:补全格式,使字符串长度为 4 的整数倍(不足补 =,最多补 3 个,实际只会补 0/1/2 个) + int remainder = cleanStr.length() % 4; + if (remainder != 0) { + int padLength = 4 - remainder; + StringBuilder sb = new StringBuilder(cleanStr); + for (int i = 0; i < padLength; i++) { + sb.append('='); + } + cleanStr = sb.toString(); + } + + return cleanStr; + } + } \ No newline at end of file diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java index 1990488..010e14a 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java @@ -490,9 +490,20 @@ public class Prog extends AbsLayout { void release() { try { setVisibility(GONE); - View view; - for(int cc=0; cc