From c73a0d8e4cac688bea44da00e349fe4e726d8a54 Mon Sep 17 00:00:00 2001
From: Dana <Dana_Lee1016@126.com>
Date: 星期日, 30 十一月 2025 13:46:28 +0800
Subject: [PATCH] 1.加远程服务,客户端以bindservice的形式调用

---
 app/src/main/java/com/anyun/h264/H264EncodeService.java  |  421 ++++++++++++++++++++++++++++++++++++++++++++++
 key/key.jks                                              |    0 
 key/keyrk3288.jks                                        |    0 
 app/src/main/aidl/com/anyun/h264/IH264EncodeService.aidl |   28 +++
 app/src/main/aidl/com/anyun/h264/model/ResourceInfo.aidl |    7 
 app/src/main/AndroidManifest.xml                         |   10 +
 key/bjkey.jks                                            |    0 
 key/Verify.txt                                           |   41 ++++
 key/key.jks.ori                                          |    0 
 key/keysc200.jks                                         |    0 
 app/build.gradle                                         |    3 
 key/keysc626.jks                                         |    0 
 12 files changed, 510 insertions(+), 0 deletions(-)

diff --git a/app/build.gradle b/app/build.gradle
index 9215b6a..b971839 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -19,6 +19,9 @@
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
+    buildFeatures{
+        aidl true
+    }
     signingConfigs{
 
 
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 713fae5..45f8fd2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -31,6 +31,16 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        
+        <!-- H264缂栫爜鏈嶅姟 -->
+        <service
+            android:name=".h264.H264EncodeService"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="com.anyun.h264.H264EncodeService" />
+            </intent-filter>
+        </service>
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/app/src/main/aidl/com/anyun/h264/IH264EncodeService.aidl b/app/src/main/aidl/com/anyun/h264/IH264EncodeService.aidl
new file mode 100644
index 0000000..e7878d3
--- /dev/null
+++ b/app/src/main/aidl/com/anyun/h264/IH264EncodeService.aidl
@@ -0,0 +1,28 @@
+package com.anyun.h264;
+
+import com.anyun.h264.model.ResourceInfo;
+import java.util.List;
+
+/**
+ * H264缂栫爜鏈嶅姟AIDL鎺ュ彛
+ */
+interface IH264EncodeService {
+    /**
+     * 鎺у埗H264缂栫爜
+     * @param action 鎿嶄綔绫诲瀷锛�0-寮�鍚痟264鏂囦欢鍐欏叆锛�1-鍋滄h264缂栫爜骞跺仠姝㈠啓鍏ユ枃浠讹紝2-寮�鍚綉缁滄帹閫乭264锛堜笉鍐欏叆鏂囦欢锛夛紝3-鍋滄h264缂栫爜骞跺仠姝㈢綉缁滄帹閫�
+     * @param jsonConfig JSON鏍煎紡鐨勯厤缃弬鏁帮紝鍖呭惈锛歩p锛堟湇鍔″櫒IP锛夈�乸ort锛堟湇鍔″櫒绔彛锛夈�亀idth锛堣棰戝搴︼級銆乭eight锛堣棰戦珮搴︼級銆乫ramerate锛堝抚鐜囷級
+     *                  绀轰緥锛歿"ip":"192.168.1.100","port":8888,"width":640,"height":480,"framerate":25}
+     *                  濡傛灉action涓�1鎴�3锛堝仠姝㈡搷浣滐級锛屾鍙傛暟鍙负绌烘垨null
+     * @return 0-鎴愬姛锛�1-澶辫触
+     */
+    int controlEncode(int action, String jsonConfig);
+    
+    /**
+     * 鑾峰彇璧勬簮鍒楄〃
+     * @param startTime 寮�濮嬫椂闂达紙鏍煎紡锛歒YMMDDHHmmss锛孊CD缂栫爜鐨�6瀛楄妭瀛楃涓诧級
+     * @param endTime 缁撴潫鏃堕棿锛堟牸寮忥細YYMMDDHHmmss锛孊CD缂栫爜鐨�6瀛楄妭瀛楃涓诧級
+     * @return 璧勬簮鍒楄〃锛堟牴鎹甁T/T 1076-2016琛�23瀹氫箟锛�
+     */
+    List<ResourceInfo> getResourceList(String startTime, String endTime);
+}
+
diff --git a/app/src/main/aidl/com/anyun/h264/model/ResourceInfo.aidl b/app/src/main/aidl/com/anyun/h264/model/ResourceInfo.aidl
new file mode 100644
index 0000000..feeb4e1
--- /dev/null
+++ b/app/src/main/aidl/com/anyun/h264/model/ResourceInfo.aidl
@@ -0,0 +1,7 @@
+package com.anyun.h264.model;
+
+/**
+ * 闊宠棰戣祫婧愪俊鎭紙鏍规嵁JT/T 1076-2016琛�23瀹氫箟锛�
+ */
+parcelable ResourceInfo;
+
diff --git a/app/src/main/java/com/anyun/h264/H264EncodeService.java b/app/src/main/java/com/anyun/h264/H264EncodeService.java
new file mode 100644
index 0000000..c5283ca
--- /dev/null
+++ b/app/src/main/java/com/anyun/h264/H264EncodeService.java
@@ -0,0 +1,421 @@
+package com.anyun.h264;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.anyun.h264.model.ResourceInfo;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * H264缂栫爜鏈嶅姟
+ * 鎻愪緵AIDL鎺ュ彛渚涘鎴风璋冪敤锛岀敤浜庢帶鍒禜264缂栫爜鍜屾煡璇㈣祫婧愬垪琛�
+ */
+public class H264EncodeService extends Service {
+    private static final String TAG = "H264EncodeService";
+    
+    private H264Encoder h264Encoder;
+    private String outputFileDirectory; // H264鏂囦欢杈撳嚭鐩綍
+    
+    // 榛樿缂栫爜鍙傛暟
+    private static final int DEFAULT_WIDTH = 640;
+    private static final int DEFAULT_HEIGHT = 480;
+    private static final int DEFAULT_FRAME_RATE = 25;
+    private static final int DEFAULT_BITRATE = 2000000; // 2Mbps
+    
+    // 榛樿鎽勫儚澶村弬鏁�
+    private static final int[] DEFAULT_CAMERA_ID_RANGE = {1, 2};
+    private static final int[] DEFAULT_RESOLUTION = {640, 480};
+    
+    // AIDL鎺ュ彛瀹炵幇
+    private final IH264EncodeService.Stub binder = new IH264EncodeService.Stub() {
+        @Override
+        public int controlEncode(int action, String jsonConfig) throws RemoteException {
+            return H264EncodeService.this.controlEncode(action, jsonConfig);
+        }
+        
+        @Override
+        public List<ResourceInfo> getResourceList(String startTime, String endTime) throws RemoteException {
+            return H264EncodeService.this.getResourceList(startTime, endTime);
+        }
+    };
+    
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.d(TAG, "H264EncodeService created");
+        
+        // 鍒濆鍖栬緭鍑烘枃浠剁洰褰曪紙浣跨敤搴旂敤澶栭儴瀛樺偍鐩綍锛�
+        outputFileDirectory = getExternalFilesDir(null).getAbsolutePath();
+        Log.d(TAG, "Output file directory: " + outputFileDirectory);
+    }
+    
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.d(TAG, "Service bound");
+        return binder;
+    }
+    
+    @Override
+    public boolean onUnbind(Intent intent) {
+        Log.d(TAG, "Service unbound");
+        // 涓嶈嚜鍔ㄥ仠姝㈢紪鐮佸櫒锛岃瀹冨湪鏈嶅姟涓繚鎸佽繍琛�
+        return super.onUnbind(intent);
+    }
+    
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        Log.d(TAG, "Service destroyed");
+        
+        // 鍋滄骞堕噴鏀剧紪鐮佸櫒
+        stopEncoder();
+    }
+    
+    /**
+     * 缂栫爜閰嶇疆绫�
+     */
+    private static class EncodeConfig {
+        String ip;
+        int port;
+        int width;
+        int height;
+        int framerate;
+        
+        // 浠嶫SON瑙f瀽閰嶇疆
+        static EncodeConfig fromJson(String jsonConfig) throws JSONException {
+            EncodeConfig config = new EncodeConfig();
+            if (jsonConfig == null || jsonConfig.trim().isEmpty()) {
+                // 浣跨敤榛樿鍊�
+                config.width = DEFAULT_WIDTH;
+                config.height = DEFAULT_HEIGHT;
+                config.framerate = DEFAULT_FRAME_RATE;
+                config.ip = null;
+                config.port = 0;
+                return config;
+            }
+            
+            JSONObject json = new JSONObject(jsonConfig);
+            config.width = json.optInt("width", DEFAULT_WIDTH);
+            config.height = json.optInt("height", DEFAULT_HEIGHT);
+            config.framerate = json.optInt("framerate", DEFAULT_FRAME_RATE);
+            config.ip = json.optString("ip", null);
+            config.port = json.optInt("port", 0);
+            
+            return config;
+        }
+    }
+    
+    /**
+     * 鎺у埗H264缂栫爜
+     * @param action 鎿嶄綔绫诲瀷锛�0-寮�鍚痟264鏂囦欢鍐欏叆锛�1-鍋滄h264缂栫爜骞跺仠姝㈠啓鍏ユ枃浠讹紝2-寮�鍚綉缁滄帹閫乭264锛堜笉鍐欏叆鏂囦欢锛夛紝3-鍋滄h264缂栫爜骞跺仠姝㈢綉缁滄帹閫�
+     * @param jsonConfig JSON鏍煎紡鐨勯厤缃弬鏁帮紝鍖呭惈锛歩p銆乸ort銆亀idth銆乭eight銆乫ramerate
+     * @return 0-鎴愬姛锛�1-澶辫触
+     */
+    private synchronized int controlEncode(int action, String jsonConfig) {
+        Log.d(TAG, "controlEncode called with action: " + action + ", jsonConfig: " + jsonConfig);
+        
+        try {
+            EncodeConfig config = null;
+            
+            // 瀵逛簬鍋滄鎿嶄綔锛屼笉闇�瑕佽В鏋愰厤缃�
+            if (action != 1 && action != 3) {
+                try {
+                    config = EncodeConfig.fromJson(jsonConfig);
+                    Log.d(TAG, "Parsed config - width: " + config.width + ", height: " + config.height + 
+                            ", framerate: " + config.framerate + ", ip: " + config.ip + ", port: " + config.port);
+                } catch (JSONException e) {
+                    Log.e(TAG, "Failed to parse JSON config: " + jsonConfig, e);
+                    return 1; // 澶辫触
+                }
+            }
+            
+            switch (action) {
+                case 0: // 寮�鍚痟264鏂囦欢鍐欏叆
+                    return startFileEncode(config);
+                    
+                case 1: // 鍋滄h264缂栫爜骞跺仠姝㈠啓鍏ユ枃浠�
+                    return stopEncoder();
+                    
+                case 2: // 寮�鍚綉缁滄帹閫乭264锛堜笉鍐欏叆鏂囦欢锛�
+                    return startNetworkEncode(config);
+                    
+                case 3: // 鍋滄h264缂栫爜骞跺仠姝㈢綉缁滄帹閫�
+                    return stopEncoder();
+                    
+                default:
+                    Log.e(TAG, "Unknown action: " + action);
+                    return 1; // 澶辫触
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Error in controlEncode", e);
+            return 1; // 澶辫触
+        }
+    }
+    
+    /**
+     * 鍚姩鏂囦欢缂栫爜妯″紡锛堝彧鍐欏叆鏂囦欢锛屼笉杩涜缃戠粶鎺ㄩ�侊級
+     */
+    private int startFileEncode(EncodeConfig config) {
+        Log.d(TAG, "Starting file encode mode");
+        
+        // 濡傛灉缂栫爜鍣ㄥ凡缁忓湪杩愯锛屽厛鍋滄
+        if (h264Encoder != null) {
+            Log.w(TAG, "Encoder is already running, stopping it first");
+            stopEncoder();
+        }
+        
+        try {
+            // 鍒涘缓缂栫爜鍣�
+            h264Encoder = new H264Encoder();
+            
+            // 璁剧疆缂栫爜鍙傛暟锛堜娇鐢ㄩ厤缃腑鐨勫弬鏁帮級
+            int width = config != null ? config.width : DEFAULT_WIDTH;
+            int height = config != null ? config.height : DEFAULT_HEIGHT;
+            int framerate = config != null ? config.framerate : DEFAULT_FRAME_RATE;
+            h264Encoder.setEncoderParams(width, height, framerate, DEFAULT_BITRATE);
+            
+            // 璁剧疆杈撳嚭鏂囦欢
+            String fileName = "h264_" + System.currentTimeMillis() + ".h264";
+            File outputFile = new File(outputFileDirectory, fileName);
+            h264Encoder.setOutputFile(outputFile.getAbsolutePath());
+            h264Encoder.setEnableFileOutput(true); // 鍚敤鏂囦欢杈撳嚭
+            
+            // 绂佺敤缃戠粶浼犺緭
+            h264Encoder.setEnableNetworkTransmission(false);
+            
+            // 鍒濆鍖栧苟鍚姩锛堜娇鐢ㄩ厤缃腑鐨勫垎杈ㄧ巼锛�
+            int[] resolution = {width, height};
+            if (h264Encoder.initialize(DEFAULT_CAMERA_ID_RANGE, null, resolution, false)) {
+                h264Encoder.start();
+                Log.d(TAG, "File encode started successfully, output file: " + outputFile.getAbsolutePath() + 
+                        ", resolution: " + width + "x" + height + ", framerate: " + framerate);
+                return 0; // 鎴愬姛
+            } else {
+                Log.e(TAG, "Failed to initialize encoder");
+                h264Encoder = null;
+                return 1; // 澶辫触
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to start file encode", e);
+            h264Encoder = null;
+            return 1; // 澶辫触
+        }
+    }
+    
+    /**
+     * 鍚姩缃戠粶鎺ㄩ�佹ā寮忥紙鍙繘琛岀綉缁滄帹閫侊紝涓嶅啓鍏ユ枃浠讹級
+     */
+    private int startNetworkEncode(EncodeConfig config) {
+        Log.d(TAG, "Starting network encode mode");
+        
+        // 濡傛灉缂栫爜鍣ㄥ凡缁忓湪杩愯锛屽厛鍋滄
+        if (h264Encoder != null) {
+            Log.w(TAG, "Encoder is already running, stopping it first");
+            stopEncoder();
+        }
+        
+        // 妫�鏌ュ繀闇�鐨勯厤缃弬鏁�
+        if (config == null || config.ip == null || config.ip.trim().isEmpty() || config.port <= 0) {
+            Log.e(TAG, "Network encode requires valid ip and port in config");
+            return 1; // 澶辫触
+        }
+        
+        try {
+            // 鍒涘缓缂栫爜鍣�
+            h264Encoder = new H264Encoder();
+            
+            // 璁剧疆缂栫爜鍙傛暟锛堜娇鐢ㄩ厤缃腑鐨勫弬鏁帮級
+            int width = config.width;
+            int height = config.height;
+            int framerate = config.framerate;
+            h264Encoder.setEncoderParams(width, height, framerate, DEFAULT_BITRATE);
+            
+            // 绂佺敤鏂囦欢杈撳嚭
+            h264Encoder.setEnableFileOutput(false);
+            
+            // 鍚敤缃戠粶浼犺緭骞惰缃湇鍔″櫒鍦板潃
+            h264Encoder.setEnableNetworkTransmission(true);
+            h264Encoder.setServerAddress(config.ip, config.port);
+            
+            // 璁剧疆鍗忚鍙傛暟锛堜娇鐢ㄩ粯璁ゅ�硷紝鍙牴鎹渶瑕佷粠閰嶇疆涓坊鍔狅級
+            // TODO: 濡傛灉闇�瑕佸湪JSON閰嶇疆涓坊鍔爏imCardNumber鍜宭ogicalChannelNumber锛屽彲浠ュ湪杩欓噷瑙f瀽
+            h264Encoder.setProtocolParams("123456789012", (byte)1);
+            
+            // 鍒濆鍖栧苟鍚姩锛堜娇鐢ㄩ厤缃腑鐨勫垎杈ㄧ巼锛�
+            int[] resolution = {width, height};
+            if (h264Encoder.initialize(DEFAULT_CAMERA_ID_RANGE, null, resolution, false)) {
+                h264Encoder.start();
+                Log.d(TAG, "Network encode started successfully, server: " + config.ip + ":" + config.port + 
+                        ", resolution: " + width + "x" + height + ", framerate: " + framerate);
+                return 0; // 鎴愬姛
+            } else {
+                Log.e(TAG, "Failed to initialize encoder");
+                h264Encoder = null;
+                return 1; // 澶辫触
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to start network encode", e);
+            h264Encoder = null;
+            return 1; // 澶辫触
+        }
+    }
+    
+    /**
+     * 鍋滄缂栫爜鍣�
+     */
+    private int stopEncoder() {
+        Log.d(TAG, "Stopping encoder");
+        
+        if (h264Encoder != null) {
+            try {
+                h264Encoder.stop();
+                h264Encoder.release();
+                h264Encoder = null;
+                Log.d(TAG, "Encoder stopped successfully");
+                return 0; // 鎴愬姛
+            } catch (Exception e) {
+                Log.e(TAG, "Error stopping encoder", e);
+                h264Encoder = null;
+                return 1; // 澶辫触
+            }
+        } else {
+            Log.w(TAG, "Encoder is not running");
+            return 0; // 鎴愬姛锛堟病鏈夎繍琛岀殑缂栫爜鍣紝瑙嗕负鎴愬姛锛�
+        }
+    }
+    
+    /**
+     * 鑾峰彇璧勬簮鍒楄〃锛堟牴鎹甁T/T 1076-2016琛�23瀹氫箟锛�
+     * @param startTime 寮�濮嬫椂闂达紙鏍煎紡锛歒YMMDDHHmmss锛�
+     * @param endTime 缁撴潫鏃堕棿锛堟牸寮忥細YYMMDDHHmmss锛�
+     * @return 璧勬簮鍒楄〃
+     */
+    private List<ResourceInfo> getResourceList(String startTime, String endTime) {
+        Log.d(TAG, "getResourceList called, startTime: " + startTime + ", endTime: " + endTime);
+        
+        List<ResourceInfo> resourceList = new ArrayList<>();
+        
+        try {
+            // 鎵弿杈撳嚭鐩綍涓殑H264鏂囦欢
+            File dir = new File(outputFileDirectory);
+            if (!dir.exists() || !dir.isDirectory()) {
+                Log.w(TAG, "Output directory does not exist: " + outputFileDirectory);
+                return resourceList;
+            }
+            
+            File[] files = dir.listFiles((dir1, name) -> name.toLowerCase().endsWith(".h264"));
+            if (files == null || files.length == 0) {
+                Log.d(TAG, "No H264 files found in directory");
+                return resourceList;
+            }
+            
+            // 瑙f瀽鏃堕棿鑼冨洿
+            Date startDate = parseTime(startTime);
+            Date endDate = parseTime(endTime);
+            
+            if (startDate == null || endDate == null) {
+                Log.e(TAG, "Invalid time format, startTime: " + startTime + ", endTime: " + endTime);
+                return resourceList;
+            }
+            
+            // 閬嶅巻鏂囦欢锛屾煡鎵惧湪鏃堕棿鑼冨洿鍐呯殑鏂囦欢
+            for (File file : files) {
+                ResourceInfo resourceInfo = createResourceInfoFromFile(file, startDate, endDate);
+                if (resourceInfo != null) {
+                    resourceList.add(resourceInfo);
+                }
+            }
+            
+            Log.d(TAG, "Found " + resourceList.size() + " resources in time range");
+            return resourceList;
+            
+        } catch (Exception e) {
+            Log.e(TAG, "Error getting resource list", e);
+            return resourceList;
+        }
+    }
+    
+    /**
+     * 浠庢枃浠跺垱寤鸿祫婧愪俊鎭紙濡傛灉鏂囦欢鍦ㄦ椂闂磋寖鍥村唴锛�
+     */
+    private ResourceInfo createResourceInfoFromFile(File file, Date startDate, Date endDate) {
+        try {
+            // 浠庢枃浠跺悕鎴栨枃浠朵慨鏀规椂闂磋幏鍙栨枃浠舵椂闂�
+            // 杩欓噷鍋囪鏂囦欢鍚嶅寘鍚椂闂存埑锛屾垨鑰呬娇鐢ㄦ枃浠朵慨鏀规椂闂�
+            Date fileDate = new Date(file.lastModified());
+            
+            // 妫�鏌ユ枃浠舵椂闂存槸鍚﹀湪鎸囧畾鑼冨洿鍐�
+            if (fileDate.before(startDate) || fileDate.after(endDate)) {
+                return null; // 涓嶅湪鏃堕棿鑼冨洿鍐�
+            }
+            
+            // 鍒涘缓璧勬簮淇℃伅瀵硅薄
+            ResourceInfo resourceInfo = new ResourceInfo();
+            
+            // 閫昏緫閫氶亾鍙凤紙榛樿鍊硷紝瀹為檯搴斾粠閰嶇疆鑾峰彇锛�
+            resourceInfo.setLogicalChannelNumber((byte) 1);
+            
+            // 寮�濮嬫椂闂村拰缁撴潫鏃堕棿锛堜娇鐢ㄦ枃浠朵慨鏀规椂闂达級
+            SimpleDateFormat bcdFormat = new SimpleDateFormat("yyMMddHHmmss", Locale.US);
+            resourceInfo.setStartTime(bcdFormat.format(fileDate));
+            // 缁撴潫鏃堕棿鍙互浣跨敤鏂囦欢淇敼鏃堕棿鍔犱笂涓�涓粯璁ゆ椂闀匡紙渚嬪1鍒嗛挓锛�
+            long fileDuration = 60000; // 榛樿1鍒嗛挓锛屽疄闄呭簲璇ユ牴鎹枃浠跺唴瀹硅绠�
+            Date endTime = new Date(fileDate.getTime() + fileDuration);
+            resourceInfo.setEndTime(bcdFormat.format(endTime));
+            
+            // 鎶ヨ鏍囧織锛堥粯璁ゅ�硷紝瀹為檯搴斾粠鏂囦欢鍏冩暟鎹幏鍙栵級
+            resourceInfo.setAlarmFlag(0L);
+            
+            // 闊宠棰戣祫婧愮被鍨嬶細2-瑙嗛
+            resourceInfo.setResourceType((byte) 2);
+            
+            // 鐮佹祦绫诲瀷锛�1-涓荤爜娴�
+            resourceInfo.setStreamType((byte) 1);
+            
+            // 瀛樺偍鍣ㄧ被鍨嬶細1-涓诲瓨鍌ㄥ櫒
+            resourceInfo.setStorageType((byte) 1);
+            
+            // 鏂囦欢澶у皬
+            resourceInfo.setFileSize(file.length());
+            
+            return resourceInfo;
+            
+        } catch (Exception e) {
+            Log.e(TAG, "Error creating resource info from file: " + file.getName(), e);
+            return null;
+        }
+    }
+    
+    /**
+     * 瑙f瀽BCD鏃堕棿瀛楃涓�
+     * @param timeStr 鏃堕棿瀛楃涓诧紙鏍煎紡锛歒YMMDDHHmmss锛�
+     * @return Date瀵硅薄锛屽鏋滆В鏋愬け璐ヨ繑鍥瀗ull
+     */
+    private Date parseTime(String timeStr) {
+        if (timeStr == null || timeStr.length() != 12) {
+            return null;
+        }
+        
+        try {
+            SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmmss", Locale.US);
+            return format.parse(timeStr);
+        } catch (ParseException e) {
+            Log.e(TAG, "Failed to parse time: " + timeStr, e);
+            return null;
+        }
+    }
+}
+
diff --git a/key/Verify.txt b/key/Verify.txt
new file mode 100644
index 0000000..f819a2e
--- /dev/null
+++ b/key/Verify.txt
@@ -0,0 +1,41 @@
+	private static PrivateKey getKey(String key, char[] password) throws Exception {
+		byte[] cabuf = new BASE64Decoder().decodeBuffer(key);
+		KeyStore keyStore = KeyStore.getInstance("PKCS12");
+		keyStore.load(new ByteArrayInputStream(cabuf), password);
+		Enumeration<String> aliases = keyStore.aliases();
+		if (!aliases.hasMoreElements()) {
+			throw new RuntimeException("no alias found");
+		}
+		String alias = aliases.nextElement();
+		PrivateKey privateKey = (RSAPrivateCrtKeyImpl) keyStore.getKey(alias, password);
+		return privateKey;
+	}
+
+	public static String sign(String data, PrivateKey key) throws Exception {
+//		MessageDigest md = MessageDigest.getInstance("SHA-256");
+		MessageDigest md = MessageDigest.getInstance("SHA-1");
+		md.update(data.getBytes("utf-8"));
+		byte[] hash = md.digest();
+//		Cipher cipher = Cipher.getInstance("RSA");
+		Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+		cipher.init(Cipher.ENCRYPT_MODE, key);
+		byte[] encrypted = cipher.doFinal(hash);
+		return HexBin.encode(encrypted);
+	}
+
+
+	public static String sign(String data, String keyString ,String pwd ) throws Exception {
+		char[] password = pwd.toCharArray();
+
+		return sign(data,getKey(keyString,password));
+	}
+
+
+	public static void main(String[] args) {
+		try{
+			String sign = sign("xuanborobot123456nullnullnull","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","27U777");
+			System.out.println(sign);
+		}catch (Exception e){
+			e.printStackTrace();
+		}
+	}
\ No newline at end of file
diff --git a/key/bjkey.jks b/key/bjkey.jks
new file mode 100644
index 0000000..35abed1
--- /dev/null
+++ b/key/bjkey.jks
Binary files differ
diff --git a/key/key.jks b/key/key.jks
new file mode 100644
index 0000000..7b43d77
--- /dev/null
+++ b/key/key.jks
Binary files differ
diff --git a/key/key.jks.ori b/key/key.jks.ori
new file mode 100644
index 0000000..3908383
--- /dev/null
+++ b/key/key.jks.ori
Binary files differ
diff --git a/key/keyrk3288.jks b/key/keyrk3288.jks
new file mode 100644
index 0000000..2f65bee
--- /dev/null
+++ b/key/keyrk3288.jks
Binary files differ
diff --git a/key/keysc200.jks b/key/keysc200.jks
new file mode 100644
index 0000000..9fd3690
--- /dev/null
+++ b/key/keysc200.jks
Binary files differ
diff --git a/key/keysc626.jks b/key/keysc626.jks
new file mode 100644
index 0000000..bb729ce
--- /dev/null
+++ b/key/keysc626.jks
Binary files differ

--
Gitblit v1.8.0